React深入(一)

2021-01-18  本文已影响0人  老夫当年也是神一般的少年

Context

使用场景

  1. 为了解决props的繁琐传递问题,Context提供一种组件间共享值的方式,不必显示通过组件数逐层传递props;
  2. 很多不同层级的组件需要访问同样一些的数据,例如获取当前认证的用户、主题或首选语言,类似于全局缓存;
  3. Context有时候可由组件组合(component composition,即把组件当做props传递)代替。

使用步骤

  1. 创建context:
    const ThemeContext = React.createContext({theme: 'light', text: '按钮'});
    ThemedButton.contextType = ThemeContext;

  2. 赋值context:
    <ThemeContext.Provider value={{theme: 'primary', text: '提交'}}>
    这里的value值可以传字符串,数字或者对象;
    如要更新context,可以通过更新state再把state传入context的方式实现。

  3. 渲染context:
    static contextType = ThemeContext;
    // React 会往上找到最近的 theme Provider,然后使用它的值。
    return <div className={'btn '+this.props.theme}>{this.props.value}</div>

    <ThemeContext.Consumer>
    {
    context => (
    <div className={'btn '+this.context.theme}>{this.context.text}</div>
    )
    }
    </ThemeContext.Consumer>

  4. context嵌套:
    <ThemeContext.Provider value={theme}>
    <UserContext.Provider value={signedInUser}>
    <Layout />
    </UserContext.Provider>
    </ThemeContext.Provider>

    // 一个组件可能会消费多个 context
    function Content() {
    return (
    <ThemeContext.Consumer>
    {theme => (
    <UserContext.Consumer>
    {user => (
    <ProfilePage user={user} theme={theme} />
    )}
    </UserContext.Consumer>
    )}
    </ThemeContext.Consumer>
    );

Refs转发

使用场景

  1. 需要将 ref 自动地通过组件传递到其一子组件;
  2. 父组件通过React.createRef()生成传入,子组件通过React.forwardRef((props, ref) => ())接收渲染。

Fragments

  1. 一个组件返回多个元素。Fragments 允许你将子列表分组,而无需向 DOM 添加额外节点,
    如return (
    <React.Fragment>
    <ChildA />
    <ChildB />
    <ChildC />
    </React.Fragment>
    );
  2. 循环时key可以加在React.Fragment节点标签上。

高阶组件(HOC)

  1. 高阶组件是参数为组件,返回值为新组件的函数。

  2. 使用方法:
    class ShowUserPermit extends React.Component {
    constructor(props) {
    super(props);
    }
    render() {
    return (
    <div>showUserPermit... {this.props.VIP}</div>
    )
    }
    }
    class ShowUserVipInfo extends React.Component {
    constructor(props) {
    super(props);
    }
    render() {
    return (
    <div>showUserVipInfo... {this.props.VIP}</div>
    )
    }
    }

    function wrap(WrappedComponent) {
    return class reComponent extends React.Component {
    constructor(props) {
    super(props);
    this.state = {
    VIP: 1000
    }
    }
    render() {
    return <WrappedComponent VIP={this.state.VIP}/>
    }
    }
    }

    const id = document.getElementById('example');
    const OtherShowUserVipInfo = wrap(ShowUserVipInfo);
    const OtherShowUserPermit = wrap(ShowUserVipInfo);
    const ele = <React.Fragment>
    <OtherShowUserVipInfo />
    <OtherShowUserPermit />
    </React.Fragment>
    ReactDOM.render(ele, id);

  3. HOC 不会修改传入的组件,也不会使用继承来复制其行为。相反,HOC 通过将组件包装在容器组件中来组成新组件。HOC 是纯函数,没有副作用;

  4. 不要在 render 方法中使用 HOC;

深入JSX

  1. 在 JSX 类型中使用点语法:
    const MyComponents = {
    DatePicker: function DatePicker(props) {
    return <div>Imagine a {props.color} datepicker here.</div>;
    }
    }

    function BlueDatePicker() {
    return <MyComponents.DatePicker color="blue" />;
    }

  2. 用户定义的组件必须以大写字母开头;

  3. 在运行时选择类型:
    function Story(props) {
    // 错误!JSX 类型不能是一个表达式。
    return <components[props.storyType] story={props.story} />;
    }
    function Story(props) {
    // 正确!JSX 类型可以是大写字母开头的变量。
    const SpecificStory = components[props.storyType];
    return <SpecificStory story={props.story} />;
    }

  4. JavaScript 表达式可作为 Props,如<MyComponent foo={1 + 2 + 3 + 4} />;

  5. if 语句以及 for 循环不是 JavaScript 表达式,所以不能在 JSX 中直接使用,但是可以在JSX之外用;

  6. Props 默认值为 True

  7. props展开:
    const props = {firstName: 'Ben', lastName: 'Hector'};
    <Hello {...props}/> 与 <Hello firstName={props.firstName} lastName={props.lastName} />等价

  8. 如果你想渲染 false、true、null、undefined 等值,你需要先将它们转换为字符串:
    <div>My JavaScript variable is {String(myVariable)}.</div>

Portals

ReactDOM.createPortal(child, container)

  1. Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案;
  2. 第一个参数(child)是任何可渲染的 React 子元素,例如一个元素,字符串或 fragment。第二个参数(container)是一个 DOM 元素。

Render Props

  1. 在 React 组件之间使用一个值为函数的 prop 共享代码的简单技术;
  2. 具有 render prop 的组件接受一个返回 React 元素的函数,并在组件内部通过调用此函数来实现自己的渲染逻辑:
    <DataProvider render={data => (<h1>{data.target}</h1>)}/>
  3. 本质上是把一个回调函数传入到组件里,通过回调函数的参数data再次渲染指定组件;
  4. 任何被用于告知组件需要渲染什么内容的函数 prop 在技术上都可以被称为 “render prop”,不一定非要起 render 名称;
  5. 实例代码如下:
    // 以下组件跟踪 Web 应用程序中的鼠标位置
    class Man extends React.Component {
    constructor(props) {
    super(props);
    }
    render() {
    const mouse = this.props.mouse;
    return <p>人散步:当前的人的位置是 ({mouse.x}, {mouse.y})</p>
    }
    }
    class Cat extends React.Component {
    constructor(props) {
    super(props);
    }
    render() {
    const mouse = this.props.mouse;
    return <p>猫追老鼠:当前的猫的位置是 ({mouse.x}, {mouse.y})</p>
    }
    }
    class Mouse extends React.Component {
    constructor (props) {
    super(props);
    this.state = {
    x: 0,
    y: 0
    };
    this.handleMouseMove = this.handleMouseMove.bind(this);
    }
    handleMouseMove(event) {
    this.setState({
    x: event.clientX,
    y: event.clientY
    });
    }
    render() {
    return (
    <div style={{height: '10vh'}} onMouseMove={this.handleMouseMove}>
    { /<Cat mouse={this.state}/>/ }
    {
    /*
    使用 renderprop 动态决定要渲染的内容,
    而不是给出一个 <Mouse> 渲染结果的静态表示
    b
    */
    }
    {
    this.props.render(this.state,this.props.type)
    }
    </div>
    )
    }
    }
    class MouseTracker extends React.Component {
    constructor(props) {
    super(props);
    this.renderMouse = this.renderMouse.bind(this);
    }
    renderMouse(mouse,Type) {
    return <Type mouse={mouse}/>
    }
    render() {
    return (
    <div>
    <h1>移动鼠标!</h1>
    <Mouse type={Cat} render={this.renderMouse}/>
    <Mouse type={Man} render={this.renderMouse}/>
    </div>
    )
    }
    }
    const id = document.getElementById('example');
    const ele = <React.Fragment>
    <MouseTracker />
    </React.Fragment>;
    ReactDOM.render(ele, id);
上一篇下一篇

猜你喜欢

热点阅读