Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

react cookbook note #39

Open
ZWkang opened this issue Sep 3, 2019 · 0 comments
Open

react cookbook note #39

ZWkang opened this issue Sep 3, 2019 · 0 comments

Comments

@ZWkang
Copy link
Owner

ZWkang commented Sep 3, 2019

  • 无状态函数
  • JSX扩展属性
  • 解构参数
  • 条件渲染
  • 子元素类型
  • 数组做为子元素
  • 函数作为子元素
  • 渲染回调
  • 子元素传递
  • 代理组件
  • 样式组件
  • 事件转换
  • 布局组件
  • 容器组件
  • 高阶组件
  • 状态提升
  • 可控的input

  • 无状态函数
// 推崇原因在于,无状态组件很简单,我们可以将它仅仅作为函数,它的内部并不保存状态

a=> a alway a

function Test() {
    return <h1>tesrt<h1>
}

  • JSX扩展属性
扩展属性是一个JSX特性。这是用于将所有对象的属性作为JSX属性传递的语法糖。

// 写作属性的props
<main className="main" role="main">{children}</main>

// 从对象中扩展的props
<main {...{className: "main", role: "main", children}} />

// 子组件封装以后 我们可以很好地使用这种传递性做render
  • 解构参数
解构赋值是ES6的新东西

其中要了解的扩展运算符



function Test(props) {
    return <h1>{props.test}<h1>
}

function Test({test}) {
    return <h1>{test}</h1>
}

const Greeting = ({ name, ...props }) =>
  <div {...props}>Hi {name}!</div>
  
//还可以对值做过滤
const propsThrought = {
    name: 'kang'
}
const Greeting = ({ name, ...props }) =>
  <div {...props} {...propsThrought}>Hi {name}!</div>
  • 条件渲染

条件渲染演示

function Test({isRender}) {
    return isRender ? <h1>render</h1> : <h1>no render</h1>
}

  • 子元素类型
children支持多种形式渲染

string

<div>string</div>

array

<div>{[1,2,3,4,5].map(v => <span>v</span>)}</div>
// https://codesandbox.io/s/m45p31191y

function (需要与父组件协调children的输出)

function Text(props) {
  if (typeof props.children) {
    return props.children();
  } else {
    return props.children;
  }
}

<Text>{() => <div>test</div>}</Text>

// https://codesandbox.io/s/72n5jpkp36

  • 数组做为子元素
<div>{[1,2,3,4,5].map(v => <span>v</span>)}</div>
// https://codesandbox.io/s/m45p31191y


子元素是一个元素集合
  • 函数作为子元素
function (需要与父组件协调children的输出)

function Text(props) {
  if (typeof props.children) {
    return props.children();
  } else {
    return props.children;
  }
}

<Text>{() => <div>test</div>}</Text>

// https://codesandbox.io/s/72n5jpkp36
  • 渲染回调
function App() {
  return (
    <div className="App">
      <div>
        <Text>{v => RenderName(v)}</Text>
      </div>
    </div>
  );
}
function RenderName({ name }) {
  return <h1>{name}</h1>;
}
function Text(props) {
  if (typeof props.children) {
    return props.children({
      name: "ZWKang"
    });
  } else {
    return props.children;
  }
}

这种情况的好处是 父元素只充当了数据提供者。
而数据消费者权利交给了callback处理
  • 子元素传递
class SomeContextProvider extends React.Component {
  getChildContext() {
    return {some: "context"}
  }

  render() {
    // how best do we return `children`?
  }
}

// 此时选择返回子元素的方式

// option 1: 额外的div
return <div>{children}</div> // 新版本应该不是问题

// option 2: 无益的错误
return children

作者推荐 最好把子元素当成一种不透明的数据类型。React提供React.Children来适当地处理子元素。


return React.Children.only(this.props.children)

  • 代理组件
抽象某些组件公共部分形成代理组件 用来省去重复元素属性

<button type="button">

=>

const Button = props =>
  <button type="button" {...props}>
  
<Button />
// <button type="button"><button>

<Button className="CTA">Send Money</Button>
// <button type="button" class="CTA">Send Money</button>
  • 样式组件
将样式分离到各个组件中
如果我们需要这么一个组件
<button type="button" className="btn btn-primary">

=>

import classnames from 'classnames'

const PrimaryBtn = props =>
  <Btn {...props} primary />

const Btn = ({ className, primary, ...props }) =>
  <button
    type="button"
    className={classnames(
      "btn",
      primary && "btn-primary",
      className
    )}
    {...props}
  />
  
PrimaryBtn()
  ↳ Btn({primary: true})
    ↳ Button({className: "btn btn-primary"}, type: "button"})
      ↳ '<button type="button" class="btn btn-primary"></button>'

将组件在每层中进行状态的分发,以保证单个状态不至于紊乱。
也方便组合
  • 事件转换
使用一个函数 对多个事件类型进行处理

handleEvent({type}) {
  switch(type) {
    case "click":
      return require("./actions/doStuff")(/* action dates */)
    case "mouseenter":
      return this.setState({ hovered: true })
    case "mouseleave":
      return this.setState({ hovered: false })
    default:
      return console.warn(`No case for event type "${type}"`)
  }
}


在遇到问题之前,不要担心性能优化问题。真的不要。
  • 布局组件
布局组件会导致某种形式的静态DOM元素。如果有的话,它可能不需要经常更新。

<HorizontalSplit
  leftSide={<SomeSmartComponent />}
  rightSide={<AnotherSmartComponent />}
/>

虽然 HorizontalSplit 将成为这两个组件的父组件,但它永远不会是他们的所有者。我们可以告诉它永远不更新,而不会中断组件的生命周期。
(只是当前的HorizontalSplit 不会rerender  但是子组件的re render还会继续)


class HorizontalSplit extends React.Component {
  shouldComponentUpdate() {
    return false
  }

  render() {
    <FlexContainer>
      <div>{this.props.leftSide}</div>
      <div>{this.props.rightSide}</div>
    </FlexContainer>
  }
}
  • 容器组件
我们一般让处理数据  与数据状态打交道的上层组件称为容器组件

他一般是接纳无状态组件 也就是展示型组件直接render,也就是控制点移交一处


const CommentList = ({ comments }) =>
  <ul>
    {comments.map(comment =>
      <li>{comment.body}-{comment.author}</li>
    )}
  </ul>
  
 class CommentListContainer extends React.Component {
  constructor() {
    super()
    this.state = { comments: [] }
  }

  componentDidMount() {
    $.ajax({
      url: "/my-comments.json",
      dataType: 'json',
      success: comments =>
        this.setState({comments: comments}); // 数据获取
    })
  }

  render() {
    return <CommentList comments={this.state.comments} /> //render数据
  }
}
  • 高阶组件
高阶组件一般是存储一些可复用逻辑,可复用类型。

我们可以直接patch到组件内。
不过还是还注意静态方法的传递,props名字的重复,高阶组件的传递,样板代码过多。


const Greeting = ({ name }) => {
  if (!name) { return <div>Connecting...</div> }

  return <div>Hi {name}!</div>
}

const Connect = ComposedComponent =>
  class extends React.Component {
    constructor() {
      super()
      this.state = { name: "" }
    }

    componentDidMount() {
      // this would fetch or connect to a store
      this.setState({ name: "Michael" })
    }

    render() {
      return (
        <ComposedComponent
          {...this.props}
          name={this.state.name}
        />
      )
    }
  }
  
  const ConnectedMyComponent = Connect(Greeting)

这是为任何数量的无状态函数组件提供获取绑定数据的强大模式。

  • 状态提升
    子组件可以通过父组件传递的callback 去影响父组件状态
class NameContainer extends React.Component {
  render() {
    return <Name onChange={newName => alert(newName)} />
  }
}

const Name = ({ onChange }) =>
  <input onChange={e => onChange(e.target.value)} />
  
class NameContainer extends React.Component {
  constructor() {
    super()
    this.state = {name: ""}
  }

  render() {
    return <Name onChange={newName => this.setState({name: newName})} />
  }
}
  • 可控的input

受控组件常常是需要一个state来维护表单字段数据

而非受控组件常常是直接通过取得ref input元素的值进行处理


link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant