// Component to show user details
const L3: FC<UserInputProps> = ({ nationality }) => (
<strong>{nationality}</strong>
);
// Some component #2
const L2: FC<UserInputProps> = ({ nationality }) => (
<L3 nationality={nationality} />
);
// Some component #1
const L1: FC<UserInputProps> = ({ nationality }) => (
<L2 nationality={nationality} />
);
L1
⬇️
nationality
|-> L2
⬇️
...
⬇️
nationality
|-> LN
Context provides a way to pass data through the component tree without having to pass props down manually at every level
import { createContext } from "react";
const Context = createContext({
nationality: "unknown",
setNationality: (_: string) => {},
});
class App extends Component {
state = {
nationality: "Unknown",
setNationality: (v: string) =>
this.setState({ ...this.state, nationality: v }),
};
}
render() {
return (
<Context.Provider value={this.state}>
<h1>My App</h1>
<L1 />
<SomeContainer />
</Context.Provider>
);
}
import { useContext } from "react";
const L3: FC = () => {
const { nationality } = useContext(Context);
return <strong>{nationality}</strong>;
};
Use context for commonly used data only
const SomeContainer: FC<SomeContainerProps> = () => {
const ctx = useContext(context);
const btnHandler = () => {
const { nationality } = fetchUser();
ctx.nationality = nationality;
};
return <MyBtn text="Fetch user" onClick={btnHandler} />;
};
Context was designed for sharing, not for updating
Changing context forces to rerender all context consumers. If your application is big and highly depends on the context - this might heart the performance.
Context doesn't have it's own update mechanism. It's relies on the component state to track changes. You will need to create special components which will handle state just to avoid a mess.
I would like to amend this: don't use Redux until you have problems with vanilla React.
MobX based on observables and patching your components
A lot of people dislike MobX because it works like a "magic"
npm i mobx mobx-react
class UserDetailsStore {
nationality = "unknown";
constructor() {
makeAutoObservable(this); // !important
}
setNationality(v: string) {
this.nationality = v;
}
}
const userDetailsStore = new UserDetailsStore();
const L3: FC = observer(() => {
const nationality = userDetailsStore.nationality;
return <strong>{nationality}</strong>;
});
type SomeContainerProps = {};
const SomeContainer: FC<SomeContainerProps> = () => {
const btnHandler = () => {
const { nationality } = fetchUser();
userDetailsStore.setNationality(nationality);
};
return <MyBtn text="Fetch user" onClick={btnHandler} />;
};
import { configure } from "mobx";
configure({
enforceActions: "always",
computedRequiresReaction: true,
reactionRequiresObservable: true,
observableRequiresReaction: true,
disableErrorBoundaries: true
});