Reputation: 2607
The procedure for sharing data between components in a child-parent relationship is well documented and dealt with straightforwardly in the React docs. What is less obvious is the accepted way of how one shares state and arbitrary data between components that do not share a child-parent relationship. Flux is offered as a solution, and in the past I have rolled my own pub/sub system, but still there seems a great divide among reactjs developers in this arena. RxJS has been offered as a solution, and many variants on the observer pattern, but I was wondering if there was a more canonical way of managing this issue particularly in larger application where components are less tightly bound.
Upvotes: 2
Views: 1108
Reputation: 76
There is a way documented in the official React docs to share global data between unrelated components here Scaling Up with Reducer and Context it may not be 100% what you need but I see it as a very useful feature. I show how I use it in a simple app below. But see the official documents for acceptable usage.
//App.js
import {useReducer} from 'react';
import { StyleSheet, Text, View } from 'react-native';
import {SiteContext, SiteDispatchContext, siteReducer, siteInitialState} from "./components/context";
import List from './components/list'
export default function App() {
const [state, reducer] = useReducer(siteReducer, siteInitialState);
return (
<SiteContext.Provider value={state}><SiteDispatchContext.Provider value={reducer}><View style={styles.container}>
<Text>Open up App.js to start working on your app!</Text>
<List />
</View></SiteDispatchContext.Provider></SiteContext.Provider>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
//list.js
import {useContext, useState} from 'react';
import {StyleSheet, Text, TextInput, View} from 'react-native';
import {SiteContext, SiteDispatchContext} from "./context";
const List = () => {
const siteData = useContext(SiteContext);
const siteDispatch = useContext(SiteDispatchContext);
const [firstName, setFirstName] = useState('');
const end = () => {
siteData.data.user.setFirstName(firstName);
siteDispatch({type: 'update'});
}
let li = [];
const rndInt = Math.floor(Math.random() * 6) + 1;
for(let i= 0 ; i < rndInt; i++){
li.push(<ListItem />);
}
return <View><Text>{siteData.data.userData.firstName + ' ' + siteData.data.userData.lastName}</Text><TextInput onChangeText={(text)=> { setFirstName(text); }} onSubmitEditing={()=>{ end(); }}/>{li}</View>
}
export default List;
const ListItem = () => {
const siteData = useContext(SiteContext);
return <View><Text>{siteData.data.userData.lastName}</Text></View>
}
//context.js
import { createContext } from 'react';
export const SiteContext = createContext(null);
export const SiteDispatchContext = createContext(null);
export const siteReducer = (siteData, action) => {
switch (action.type) {
case 'update': {
let s = {...siteData};
s.data.userData = s.data.user.getData();
return s;
}
}
}
class User {
firstName = 'Robert';
lastName = 'Palmer'
getData = () => {
return {
firstName: this.firstName,
lastName: this.lastName
}
}
setFirstName = (name) => {
this.firstName = name;
}
setLastName = (name) => {
this.lastName = name;
}
}
const user = new User();
export const siteInitialState = {data: {user: user, userData: user.getData(), cart: null, cartData: {}} };
Upvotes: 0
Reputation: 3324
My solution has generally been to pass a callback as a prop to components that will be accepting user input. The callback executes a state change in the parent, which propagates down. For instance:
UI = React.createClass({
getInitialState() {
return {
text: ""
};
}
hello(text) {
this.setState({
text: text
});
}
render() {
return (
<div>
<TextView content={this.state.text}>
<Button onclick={() => this.hello("HELLO WORLD")}>
</div>
);
}
});
// TextView and Button are left as an exercise to the reader
I like this because each parent component is still uniquely responsible for its content, and the child components don't intrusively know anything about each other; it's all callbacks. It admittedly may not scale very well to massive react apps, but I like that there isn't a global event dispatcher managing everything, making control flow hard to follow. In this example, the UI
class will always be completely self-contained, and can be replicated as needed without any risk of name reuse.
Upvotes: 1