Dưới đây là danh sách các thư viện phổ biến liên quan đến React và Redux, kèm theo một ví dụ minh họa đơn giản cho mỗi thư viện:
- React Redux: Thư viện chính thức để kết nối Redux với React.
- Redux Thunk: Middleware để xử lý các action bất đồng bộ trong Redux.
- Redux Saga: Middleware để quản lý các side effect (tác động phụ) trong Redux, sử dụng các generator function.
- Reselect: Thư viện tạo các selector có thể tính toán lại trạng thái dựa trên trạng thái Redux.
- Redux Toolkit: Bộ công cụ chính thức để viết mã Redux một cách hiệu quả hơn.
- Redux Logger: Middleware để log các action và trạng thái Redux cho mục đích debug.
Ví dụ minh họa
1. React Redux
Cài đặt:
npm install react-redux
Ví dụ:
import React from 'react';
import { Provider, useDispatch, useSelector } from 'react-redux';
import { createStore } from 'redux';
// Actions
const INCREMENT = 'INCREMENT';
const increment = () => ({ type: INCREMENT });
// Reducer
const initialState = { count: 0 };
const counterReducer = (state = initialState, action: any) => {
switch (action.type) {
case INCREMENT:
return { ...state, count: state.count + 1 };
default:
return state;
}
};
// Store
const store = createStore(counterReducer);
const Counter: React.FC = () => {
const count = useSelector((state: any) => state.count);
const dispatch = useDispatch();
return (
<div>
<p>Count: {count}</p>
<button onClick={() => dispatch(increment())}>Increment</button>
</div>
);
};
const App: React.FC = () => (
<Provider store={store}>
<Counter />
</Provider>
);
export default App;
2. Redux Thunk
Cài đặt:
npm install redux-thunk
Ví dụ:
import { applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
import { Provider, useDispatch, useSelector } from 'react-redux';
import React from 'react';
// Actions
const FETCH_DATA = 'FETCH_DATA';
const fetchData = () => async (dispatch: any) => {
const data = await fetch('/api/data').then((res) => res.json());
dispatch({ type: FETCH_DATA, payload: data });
};
// Reducer
const dataReducer = (state = { data: [] }, action: any) => {
switch (action.type) {
case FETCH_DATA:
return { ...state, data: action.payload };
default:
return state;
}
};
// Store
const store = createStore(dataReducer, applyMiddleware(thunk));
const DataComponent: React.FC = () => {
const data = useSelector((state: any) => state.data);
const dispatch = useDispatch();
React.useEffect(() => {
dispatch(fetchData());
}, [dispatch]);
return <div>{JSON.stringify(data)}</div>;
};
const App: React.FC = () => (
<Provider store={store}>
<DataComponent />
</Provider>
);
export default App;
3. Redux Saga
Cài đặt:
npm install redux-saga
Ví dụ:
import { createStore, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga';
import { takeEvery, call, put } from 'redux-saga/effects';
import { Provider, useDispatch, useSelector } from 'react-redux';
import React from 'react';
// Actions
const FETCH_DATA_REQUEST = 'FETCH_DATA_REQUEST';
const FETCH_DATA_SUCCESS = 'FETCH_DATA_SUCCESS';
const fetchDataRequest = () => ({ type: FETCH_DATA_REQUEST });
function* fetchDataSaga() {
const data = yield call(() => fetch('/api/data').then((res) => res.json()));
yield put({ type: FETCH_DATA_SUCCESS, payload: data });
}
// Reducer
const dataReducer = (state = { data: [] }, action: any) => {
switch (action.type) {
case FETCH_DATA_SUCCESS:
return { ...state, data: action.payload };
default:
return state;
}
};
// Saga
function* rootSaga() {
yield takeEvery(FETCH_DATA_REQUEST, fetchDataSaga);
}
// Store
const sagaMiddleware = createSagaMiddleware();
const store = createStore(dataReducer, applyMiddleware(sagaMiddleware));
sagaMiddleware.run(rootSaga);
const DataComponent: React.FC = () => {
const data = useSelector((state: any) => state.data);
const dispatch = useDispatch();
React.useEffect(() => {
dispatch(fetchDataRequest());
}, [dispatch]);
return <div>{JSON.stringify(data)}</div>;
};
const App: React.FC = () => (
<Provider store={store}>
<DataComponent />
</Provider>
);
export default App;
4. Reselect
Cài đặt:
npm install reselect
Ví dụ:
import { createSelector } from 'reselect';
import { createStore } from 'redux';
import { Provider, useSelector } from 'react-redux';
import React from 'react';
// Reducer
const initialState = { items: [1, 2, 3, 4, 5] };
const itemsReducer = (state = initialState, action: any) => {
switch (action.type) {
default:
return state;
}
};
// Store
const store = createStore(itemsReducer);
// Selector
const selectItems = (state: any) => state.items;
const selectEvenItems = createSelector(selectItems, (items) => items.filter((item) => item % 2 === 0));
const ItemsComponent: React.FC = () => {
const evenItems = useSelector(selectEvenItems);
return <div>{JSON.stringify(evenItems)}</div>;
};
const App: React.FC = () => (
<Provider store={store}>
<ItemsComponent />
</Provider>
);
export default App;
5. Redux Toolkit
Cài đặt:
npm install @reduxjs/toolkit
Ví dụ:
import { configureStore, createSlice, PayloadAction } from '@reduxjs/toolkit';
import { Provider, useDispatch, useSelector } from 'react-redux';
import React from 'react';
// Slice
const counterSlice = createSlice({
name: 'counter',
initialState: { count: 0 },
reducers: {
increment: (state) => {
state.count += 1;
},
decrement: (state) => {
state.count -= 1;
},
incrementByAmount: (state, action: PayloadAction<number>) => {
state.count += action.payload;
},
},
});
// Store
const store = configureStore({
reducer: {
counter: counterSlice.reducer,
},
});
const { increment, decrement, incrementByAmount } = counterSlice.actions;
const Counter: React.FC = () => {
const count = useSelector((state: any) => state.counter.count);
const dispatch = useDispatch();
return (
<div>
<p>Count: {count}</p>
<button onClick={() => dispatch(increment())}>Increment</button>
<button onClick={() => dispatch(decrement())}>Decrement</button>
<button onClick={() => dispatch(incrementByAmount(5))}>Increment by 5</button>
</div>
);
};
const App: React.FC = () => (
<Provider store={store}>
<Counter />
</Provider>
);
export default App;
6. Redux Logger
Cài đặt:
npm install redux-logger
Ví dụ:
import { createStore, applyMiddleware } from 'redux';
import logger from 'redux-logger';
import { Provider, useDispatch, useSelector } from 'react-redux';
import React from 'react';
// Actions
const INCREMENT = 'INCREMENT';
const increment = () => ({ type: INCREMENT });
// Reducer
const initialState = { count: 0 };
const counterReducer = (state = initialState, action: any) => {
switch (action.type) {
case INCREMENT:
return { ...state, count: state.count + 1 };
default:
return state;
}
};
// Store
const store = createStore(counterReducer, applyMiddleware(logger));
const Counter: React.FC = () => {
const count = useSelector((state: any) => state.count);
const dispatch = useDispatch();
return (
<div>
<p>Count: {count}</p>
<button onClick={() => dispatch(increment())}>Increment</button>
</div>
);
};
const App: React.FC = () => (
<Provider store={store}>
<Counter />
</Provider>
);
export default App;
Đây là một số ví dụ cơ bản minh họa cách sử dụng các thư viện phổ biến liên quan đến React và Redux. Mỗi ví dụ đều cung cấp một cách tiếp cận khác nhau để quản lý trạng thái và side effects trong ứng dụng React.