He estado tratando de entender la nueva API React Context y estaba jugando con ella. Solo quería verificar un caso simple: lo que se vuelve a representar cuando se actualizan los datos de un proveedor.
Mira este pequeño ejemplo en Codesandbox
Entonces, en mi ejemplo, tengo un componente de App , que tiene un estado similar a este:
this.state = { number - A random number text - A static text } Creo un nuevo React Context desde aquí que contiene number y el text del estado y paso los valores a dos Consumers Number y Text .
Entonces, mi suposición es que si el número aleatorio se actualiza, cambiará el contexto y ambos componentes deberían desencadenar una nueva representación.
Pero en realidad, el valor se está actualizando pero no está ocurriendo una nueva representación.
Entonces, mi pregunta -
¿Se actualizan al contexto que no se propagan a través de las representaciones habituales? Como no puedo ver mis registros/cambios de color cuando cambia el contexto.
¿Todos los consumidores de ese Proveedor están actualizados o no?
¿Se actualizan al contexto que no se propagan a través de las representaciones habituales? Como no puedo ver mis registros/cambios de color cuando cambia el contexto.
Las actualizaciones de los valores de contexto no desencadenan una nueva representación para todos los elementos secundarios del proveedor, sino solo los componentes que se representan desde el Consumidor, por lo que en su caso, aunque el componente numérico contiene el componente Consumidor, el componente Número no se vuelve a representar , más bien solo la función de representación dentro del Consumidor y, por lo tanto, el valor cambia en las actualizaciones de contexto. De esta manera, tiene un gran rendimiento, ya que no desencadena re-renderizaciones para todos sus elementos secundarios.
¿Todos los consumidores de ese proveedor están actualizados o no?
Todos los consumidores de ese proveedor pasarán por un ciclo de actualización, pero la comparación del DOM virtual de reacción decide si vuelven a renderizar o no. Una demostración de esto se puede ver en la consola para este sandbox
EDITAR
Lo que debe asegurarse es que los componentes se representan como elementos secundarios del componente ContextProvider y le está pasando controladores en lugar de representarlos en línea y actualizar el estado de ContextProvider porque eso activará una nueva representación de todos los componentes que están dentro el proveedor de ContextProvider
Uso eficiente
Aplicación.js
constructor() { super(); this.state = { number: Math.random() * 100, text: "testing context api" updateNumber: this.updateNumber, }; } render() { return ( <AppContext.Provider value={this.state} > {this.props.children} </AppContext.Provider> ); }índice.js
class Data extends React.Component { render() { return ( <div> <h1>Welcome to React</h1> <Number /> <Text /> <TestComp /> <AppContext.Consumer> {({ updateNumber }) => ( <button onClick={updateNumber}>Change Number </button> )} </AppContext.Consumer> </div> ); } } const rootElement = document.getElementById("root"); ReactDOM.render( <App> <Data /> </App>, rootElement );Uso de menor rendimiento
Aplicación.js
class App extends Component { constructor() { super(); this.state = { number: Math.random() * 100, text: "testing context api" }; } updateNumber = () => { const randomNumber = Math.random() * 100; this.setState({ number: randomNumber }); }; render() { return ( <AppContext.Provider value={this.state}> <div> <h1>Welcome to React</h1> <Number /> <Text /> <TestComp /> <button onClick={this.updateNumber}>Change Number </button> </div> </AppContext.Provider> ); } }Aquí hay una actualización para sus preguntas basada en useContext Hook:
const value = useContext(MyContext)Cuando se actualice el
<MyContext.Provider>más cercano por encima del componente, este Hook activará una nueva representación con el últimovaluede contexto pasado a ese proveedor deMyContext. Incluso si un ancestro usaReact.memooshouldComponentUpdate, aún se producirá una nueva representación comenzando en el componente mismo usandouseContext.Un componente que llame a
useContextsiempre se volverá a representar cuando cambie el valor del contexto . Si volver a renderizar el componente es costoso, puede optimizarlo mediante la memorización.
Entonces, dado el siguiente ejemplo de código, los componentes Number y Text se volverán a representar con cada cambio de valor de contexto, ya que ambos contienen directamente useContext(AppContext) .
const AppContext = React.createContext(); const Number = React.memo(props => { const renderCount = useRenderCount(); const contextNo = React.useContext(AppContext); return ( <div style={{ backgroundColor: `${randomColor()}` }}> Number: rendered {renderCount.current} times. </div> ); }); const Text = React.memo(() => { const renderCount = useRenderCount(); const context = React.useContext(AppContext); return ( <div style={{ backgroundColor: `${randomColor()}` }}> Text: rendered {renderCount.current} times. I rerender with context value changes! </div> ); }); const App = () => { const [ctxVal, setCtxVal] = React.useState(0); const [prop, setProp] = React.useState(0); return ( <AppContext.Provider value={ctxVal}> <Number prop={prop} /> <Text /> <button onClick={() => setCtxVal(ctxVal + 1)}> Change context value </button> <button onClick={() => setProp(prop + 1)}> Only change prop in Number </button> </AppContext.Provider> ); }; function useRenderCount() { const renderCount = React.useRef(1); React.useEffect(() => { renderCount.current += 1; }); return renderCount; } function randomColor() { const letters = "0123456789ABCDEF"; let color = "#"; for (let i = 0; i < 6; i++) color += letters[Math.floor(Math.random() * 16)]; return color; } ReactDOM.render(<App />, document.getElementById("root")); <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js" integrity="sha256-32Gmw5rBDXyMjg/73FgpukoTZdMrxuYW7tj8adbN8z4=" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js" integrity="sha256-bjQ42ac3EN0GqK40pC9gGi/YixvKyZ24qMP/9HiGW7w=" crossorigin="anonymous"></script> <div id="root"></div>