Redux: Sử dụng selector
Bài đăng này đã không được cập nhật trong 4 năm
Khi học qua Redux có thể bạn đã từng nghe "giữ state đơn giản nhất, và sử dụng nó khi cần', một phần trong bài học đó bạn cũng có thể đã sử dụng đến redux selector.
Một selector function nhận vào input là state và trả về một giá trị mong muốn dựa trên state đó. ví dụ
const selectEntities = state => state.entities;
function selectItemIds(state) {
    return state.items.map(item => item.id);
}
const selectSomeSpecificField = state => state.some.deeply.nested.field;
function selectItemsWhoseNamesStartWith(items, namePrefix) {
     const filteredItems = items.filter(item => item.name.startsWith(namePrefix));
     return filteredItems;
}
Bạn có thể sử dụng selector ở khắp mọi nơi miễn sao nó là một component, một selector thường bắt đầu với prefix get[something] hoặc select[something] hoặc có thể là một suffix [something]Selector.
Việc render:
- 
Khi một actionđượcdispatch,useSelectorsẽ thực hiện so sánh giữa kết quả trước đó và kết quả hiện tại, nếu khác, component bị force đểre-render.
- 
useSelectorsử dụng so sánh===chứ không dùng phương phápshallow compare
- 
Lý do sử dụng useSelector:- Tái sử dụng, selectorcó thể được sử dụng ở nhiều nơi, nhiềucomponentkhác nhau mà không cần khai báo lại
- Tinh gọn, chúng ta có một statecarchứaname,brand,year, nếu muốn lấybrandthì chỉ cần selectorgetBrandCarlà dễ hiểu
- Cập nhật, khi structurecủaredux storethay đổi, chúng ta chỉ cần cập nhật lạiselectorlà xong
 // Previous ... store = { car: {id: 1, brand: "Vinfast", name: "Lux A", year: "2019"} } // selector export const getCarBrand = state => state.car.brand //==> After ... store = { car: {id: 2, company: "Vinfast", name: "Lux A", year: "2019"} } //selector export const getCarCompany = state => state.car.company
- Tái sử dụng, 
Sử dụng:
Vì selector sử dụng phương thức so sánh "==="  nên nếu trả về array, object thông qua việc tính toán thì component sẽ bị trigger re-render. Trong lúc re-render cho dù data không thay đổi, thì hàm selectFilteredSortedTransformedData vẫn bị gọi lại:
const selectFilteredSortedTransformedData = state => {
    const filteredData = expensiveFiltering(state.data);
    const sortedData = expensiveSorting(filteredData);
    const transformedData = expensiveTransformation(sortedData);
    return transformedData;
}
Cách giải quyết vấn đề, sử dụng reselect:
const selectSomeData = state => state.someData;
    const selectFilteredSortedTransformedData = createSelector(
        selectSomeData,
        (someData) => {
             const filteredData = expensiveFiltering(someData);
             const sortedData = expensiveSorting(filteredData);
             const transformedData = expensiveTransformation(sortedData);
             return transformedData;
        })
Lưu ý:
- 
Nếu selectorcóinputlà 1propcủacomponenthãy đưaselectorra ngoàicomponent... const selectCar = (state, carId) => cars.find(car => car.id === carId); const selectCarById = createSelector( [selectCar], car => expensiveTransformation(car) ); export const CarDetails = ({ carId }) => { const car = useSelector(state => selectCarById(state, carId)); return <div>{car.name}</div> };
- 
Nhiều instancecủacomponent: Khi mộtselectorđược sử dụng trong nhiềuinstancecủa mộtcomponentvà cũng phụ thuộc vàoprop, VD:<CarDetails carId={1}> <CarDetails carId={2}>Điều ta cần làm bây giờ là hãy chắc chắn mỗi instance componentcó mộtinstance selectorriêng biệt, như ví dụ ở trên thì không đúng vì 2instanceđều trỏ dùng chunginstance selector.Giải pháp, sử dụng useMemo... const selectCar = (state, carId) => cars.find(car => car.id === carId); const selectCarById = createSelector( [selectCar], car => expensiveTransformation(car) ); export const CarDetails = ({ carId }) => { const selectCarMemo = useMemo(selectCarById, []) const car = useSelector(state => selectCarMemo(state, carId)); return <div>{car.name}</div> };Và bây giờ mỗi instance của CarDetailssẽ có một instance củaselectorkhác nhau
All rights reserved
 
  
 