React Context

2020-12-15  本文已影响0人  Suki_Yang

Context

Context provides a way to pass data through the component tree without having to pass props down manually at every level.

API

React.createContext
const MyContext = React.createContext(defaultValue);
Context.Provider
<MyContext.Provider value={/* some value */}>
Class.contextType
class MyClass extends React.Component {
    componentDidMount() {
        let value = this.context;
    }
    componentDidUpdate() {
        let value = this.context;
    }
    componentWillUnmount() {
        let value = this.context;
    }
    render() {
        let value = this.context;
    }
}
//The contextType property on a class can be assigned a Context object created by React.createContext()
MyClass.contextType = MyContext;
Context.Consumer
<MyContext.Consumer>
    {value => /* render something based on the context value */}
</MyContext.Consumer>

The function receives the current context value and returns a React node.

Context.displayName

Context object accepts a displayName string property. React DevTools uses this string to determine what to display for the context.

const MyContext = React.createContext(/* some value */);
MyContext.displayName = 'MyDisplayName';

<MyContext.Provider> // "MyDisplayName.Provider" in DevTools
<MyContext.Consumer> // "MyDisplayName.Consumer" in DevTools

Example

const ThemeContext = React.createContext('light');

class App extends React.Component {
    render() {
        return (
            <ThemeContext.Provider value="dark">
                <Toolbar />
            </ThemeContext.Provider>
        );
    }
}

function Toolbar() {
    return (
        <div>
            <ThemedButton />
        </div>
    );
}

class ThemedButton extends React.Component {
    static contextType = ThemeContext;
    render() {
        return <Button theme={this.context} />;
    }
}
Dynamic Context
//theme-context.js
export const theme = {
    light: {
        foreground: '#000000',
        background: '#eeeeee'
    },
    dark: {
        foreground: '#ffffff',
        background: '#222222'
    }
};

export const ThemeContext = React.createContext(themes.dark);
//themed-button.js
import {ThemeContext} from './theme-context';

class ThemedButton extends React.Component {
    render() {
        let props = this.props;
        let theme = this.context;
        return (
            <button
                {...props}
                style={{backgroundColor: theme.background}} 
            />
        );
    }
}
ThemedButton.contextType = ThemeContext;

export default ThemedButton;
//app.js
import {ThemeContext, themes} from './theme-context';
import ThemedButton from './themed-button';

function Toolbar(props) {
    return (
        <ThemedButton onClick={props.changeTheme}>
            Change Theme
        </ThemedButton>
    );
}

class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            theme: themes.light
        };
    }
    
    this.toggleTheme = () => {
        this.setState(state => ({
            theme: state.theme === themes.dark ? themes.light : themes.dark
        }));
    };
    
    render() {
        return (
            <Page>
                <ThemeContext.Provider value={this.state.theme}>
                    <Toolbar changeTheme={this.toggleTheme}/>
                </ThemeContext.Provider>
                <section>
                    <ThemedButton />
                </section>
            </Page>
        );
    }
}

ReactDOM.render(<App />, document.root);
Updating Context from a Nested Component
//theme-context.js
export const ThemeContext = React.createContext({
   theme: themes.dark,
   toggleTheme: () => {}
});
//theme-toggler-button.js
import {ThemeContext} from './theme-context';

function ThemeTogglerButton() {
    return (
        <ThemeContext.Consumer>
            {({theme, toggleTheme}) => (
                <button
                    onClick={toggleTheme}
                    style={{backgroundColor: theme.background}}
                >
                    Toggle Theme
                </button>
            )}
        </ThemeContext.Consumer>
    );
}

export default ThemeTogglerButton;
//app.js
import {ThemeContext, themes} from './theme-context';
import ThemeTogglerButton from './theme-toggler-button';

class App extends React.Component {
    constructor(props) {
        super(props);
        
        this.toggleTheme = () => {
            this.setState(state => ({
                theme: state.theme === themes.dark ? themes.light : themes.dark
            }));
        }
        
        this.state = {
            theme: themes.light,
            toggleTheme: this.toggleTheme
        };
        
        render() {
            return (
                <ThemeContext.Provider value={this.state}>
                    <Content />
                </ThemeContext.Provider>
            );
        }
    }
}

function Content() {
    return (
        <div>
            <ThemeTogglerButton />
        </div>
    );
}

ReactDOM.render(<App />, document.root);
Consuming Multiple Contexts

To keep context re-rendering fast, React needs to make each context consumer a separate node in the tree.

const ThemeContext = React.createContext('light');

const UserContext = React.createContext({name: 'Guest'});

class App extends React.Component {
    render() {
        const {signedInUser, theme} = this.props;
        
        return (
            <ThemeContext.Provider value={theme}>
                <UserContext.Provider value={signedInUser}>
                    <Layout />
                </UserContext.Provider>
            </ThemeContext.Provider>
        );
    }
}

function Layout() {
    return (
        <div>
            <Sidebar />
            <Content />
        </div>
    );
}

function Content() {
    return (
        <ThemeContext.Consumer>
            {theme => (
                <UserContext.Consumer>
                    {user => (
                        <ProfilePage user={user} theme={theme} />
                    )}
                </UserContext.Consumer>
            )}
        </ThemeContext.Consumer>
    );
}
上一篇下一篇

猜你喜欢

热点阅读