This project aims to learn and practice various state management methods in React, including basic React state management, Context API, Hooks (useEffect
, useContext
, useReducer
, useRef
, useCallback
, useMemo
), and Redux.
React key concepts include components, state, and props. Components are the building blocks of React applications, state is the internal data of a component, and props are the external inputs to a component.
To start the project, follow these steps:
-
Clone the repository:
git clone https://github.com/chile109/ReactStatePractice.git
-
Navigate to the project directory:
cd ReactStatePractice
-
Install the dependencies:
npm install
-
Start the development server:
npm run start
useState
is a Hook that allows you to add state to function components. It returns a state variable and a function to update it.
const [state, setState] = useState(initialState);
useEffect
is a Hook that allows you to perform side effects in function components. It takes a function and a dependency array.
useEffect(() => {
// Your side effect code
}, [dependencies]);
useContext
is a Hook that allows you to subscribe to context within a function component. It takes a context object and returns the current context value.
const value = useContext(MyContext);
useReducer
is a Hook that allows you to manage state using a reducer function. It takes a reducer and an initial state, returning the current state and a dispatch function.
const [state, dispatch] = useReducer(reducer, initialState);
useRef
is a Hook that returns a mutable ref object. The .current
property can hold a mutable value that persists across renders.
const ref = useRef(initialValue);
useCallback
returns a memoized callback function, and useMemo
returns a memoized value. They are used to optimize performance and prevent unnecessary re-renders.
const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
The Context API allows you to pass data through the component tree without manually passing props at every level. Create a context object and use a Provider
to supply the data, and use useContext
or Context.Consumer
to consume it.
const MyContext = createContext(defaultValue);
<MyContext.Provider value={value}>
<MyComponent />
</MyContext.Provider>
Redux is a state management library for JavaScript applications. It stores the application state in a global object and allows state updates via dispatching actions. Key concepts include Store, Action, and Reducer.
npm install redux react-redux @reduxjs/toolkit
const store = createStore(reducer);
store.dispatch({ type: 'ACTION_TYPE', payload: value });
Here's a simple example using Redux to manage state:
// actions.js
export const changeColor = () => ({ type: 'CHANGE_COLOR' });
export const changeText = () => ({ type: 'CHANGE_TEXT' });
// reducer.js
const initialState = {
color: 'blue',
text: 'Hello, World!',
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case 'CHANGE_COLOR':
return { ...state, color: state.color === 'blue' ? 'red' : 'blue' };
case 'CHANGE_TEXT':
return { ...state, text: state.text === 'Hello, World!' ? 'Goodbye, World!' : 'Hello, World!' };
default:
return state;
}
};
// store.js
import { createStore } from 'redux';
import reducer from './reducer';
const store = createStore(reducer);
export default store;
Combining Context and Redux to manage color and text states, while using useRef
to track click counts.
// ColorTextContext.js
import React, { createContext, useRef, useMemo, useCallback } from 'react';
import { useDispatch } from 'react-redux';
import { changeColor, changeText } from '../Redux/Action';
export const ColorTextContext = createContext();
export const ColorTextProvider = ({ children }) => {
const colorClickRef = useRef(0);
const textClickRef = useRef(0);
const dispatch = useDispatch();
const incrementColorClicks = useCallback(() => {
colorClickRef.current += 1;
}, []);
const incrementTextClicks = useCallback(() => {
textClickRef.current += 1;
}, []);
const contextValue = useMemo(() => ({
colorClicks: colorClickRef.current,
textClicks: textClickRef.current,
incrementColorClicks,
incrementTextClicks,
changeColor: () => {
dispatch(changeColor());
incrementColorClicks();
},
changeText: () => {
dispatch(changeText());
incrementTextClicks();
},
}), [dispatch, incrementColorClicks, incrementTextClicks]);
return (
<ColorTextContext.Provider value={contextValue}>
{children}
</ColorTextContext.Provider>
);
};
// ColorTextDisplay.js
import React, { useContext, useEffect } from 'react';
import { useSelector } from 'react-redux';
import { ColorTextContext } from '../Context/ColorTextContext';
const ColorTextDisplay = () => {
const { colorClicks, textClicks } = useContext(ColorTextContext);
const color = useSelector(state => state.color);
const text = useSelector(state => state.text);
useEffect(() => {
console.log(`Color changed to: ${color}`);
}, [color]);
useEffect(() => {
console.log(`Text changed to: ${text}`);
}, [text]);
return (
<div>
<h1 style={{ color }}>{text}</h1>
<p>Color change clicks: {colorClicks}</p>
<p>Text change clicks: {textClicks}</p>
</div>
);
};
export default ColorTextDisplay;
// ColorTextButton.js
import React, { useContext } from 'react';
import { ColorTextContext } from '../Context/ColorTextContext';
const ColorTextButton = () => {
const { changeColor, changeText } = useContext(ColorTextContext);
return (
<div>
<button onClick={changeColor}>Change Color</button>
<button onClick={changeText}>Change Text</button>
</div>
);
};
export default ColorTextButton;