首页
Preview

我的老板:你根本不会React!😠

前言

我已经使用 React 工作了很多年,我确信自己对它非常了解,但最近我的老板对我说,“你根本不懂 React,你什么都不知道。”

我对他很生气,但他指出了我的程序中存在的三个漏洞。

1. 你知道如何使用“&&”吗?

在 React 程序中,我经常使用“&&”运算符来决定是否显示内容,如下所示:

const App = () => {
  const [ list, setList ] = useState([])

  // Simulation request data
  setTimeout(() => {
    setList([ 'fatfish', 'medium' ])
  }, 2000)

  return (
    <div className="app">{ list.length && <List /> }</div>
  )
}

我的老板: “你不知道‘&&’运算符的特点吗?当请求未成功返回时,会直接渲染‘0’。”

我不相信,因为我一直这样写代码,从来没有犯过错误。为了证明老板错了,我写了以下示例:

const List = ({ list = [] }) => {
  return (
    <div className="name-list-container">
      {
        list.map((name) => {
          return <div className="name-list-item">{ name }</div>
        })
      }
    </div>
  )
}

const App = () => {
  const [ list, setList ] = React.useState([ ])
  
  // Simulation request data
  setTimeout(() => {
    setList([ 'fatfish', 'medium' ])  
  }, 3000)
  
  return (
    list.length && <List list={ list }/>
  )
}

ReactDOM.render(<App />, document.getElementById('app'))

天哪!我的老板是对的,页面一开始显示0,3秒后才显示列表。

为什么?

提示:“一组布尔操作数的逻辑 AND(逻辑连词)仅当所有操作数都为 true 时才为 true。否则,它将为 false。”

更一般地,如果从左到右评估时遇到第一个 falsy 操作数,则运算符返回该操作数的值,否则如果它们都是 truthy,则返回最后一个操作数的值。

几个例子

const x1 = 0
const x2 = 'fatfish'
const x3 = 1
const x4 = 'medium'
console.log(x1 && x2) // 0
console.log(x3 && x4) // medium

现在我终于明白了为什么像那样写代码会导致错误。原因如下:

list.length && <List list={ list } /> 
0 && <List list={ list } /> // 0

如何解决?

我发现了三种解决这个问题的方法。我希望你不要犯和我一样的错误。

// 1. Convert list.length to boolean
!!list.length && <List list={ list }/>
  
// 2. Use ternary expressions and null
list.length ? <List list={ list }/> : null

// 3. Controlled by specific logic
list.length >= 1 && <List list={ list }/>

2. “props.children”的奇怪行为

我猜你也写过类似的代码。当将内容传递给<Container/>组件时,“children” 将被显示。否则,将显示一个空的提示框。如下所示:

const Container = ({ children }) => {
  if (children) {
    return (
      <div className="children-container">
        <p>The content of children is:</p>
        { children }
      </div>
    ) 
  } else {
    return (
      <div className="empty">empty</div>
    )
  }
}

我的老板:“你必须谨慎使用‘children’属性,它会导致逻辑异常!就像下面这些情况一样。”

1. 空列表数据

你认为这个示例会显示什么——“empty”?

**不幸的是,答案是另一个。**你也觉得难以置信吗?朋友们,我们必须非常小心地使用 props.children。否则,老板可能会扣你的工资。

props.children

const Container = ({ children }) => {
  if (children) {
    return (
      <div className="children-container">
        <p>The content of children is:</p>
        { children }
      </div>
    ) 
  } else {
    return (
      <div className="empty">empty</div>
    )
  }
}
const App = () => {
  const [ list, setList ] = React.useState([])
  
  return (
    <Container>
      {
        list.map((name) => {
          return <div className="name-item">{ name }</div>  
        })
      }
    </Container>
  )
}
ReactDOM.render(<App />, document.getElementById('app'))

为什么?

让我们在“Container”组件中添加一行代码,并尝试打印出子元素!

const Container = ({ children }) => {
  console.log(children, 'children')
  // ...
}

是的,你是对的。此时,“children”是一个空数组,因此显示“children 的内容是:”而不是“empty”。

如何解决?

使用React.Children.toArray来解决这个问题非常容易,然后你将看到“empty”被显示。因此,如果你确实需要使用 children 作为条件判断,我建议你使用这种方法!

const Container = ({ children }) => {
  // if (children) {
  // Pay attention here
  if (React.Children.toArray(children).length) {  
    return (
      <div className="children-container">
        <p>The content of children is:</p>
        { children }
      </div>
    ) 
  } else {
    return (
      <div className="empty">empty</div>
    )
  }
}

3. 挂载和更新的问题

在 React 中,通过状态切换组件是很常见的,但这个小东西也可能让你感到困惑。

在下面的代码中,你认为当你切换名称的值时,一个 Demo 组件将被卸载,另一个将被挂载吗?

class Demo extends React.Component {
  componentDidMount() {
    console.log('componentDidMount', this.props.name);
  }
  componentDidUpdate() {
    console.log('componentDidUpdate', this.props.name);
  }
  
  render () {
    return (
      <div>
        { this.props.name }
      </div>
    )
  }
}
const App = () => {
  const [ name, setName ] = React.useState('fatfish')
  const onClick = () => {
    setName(name === 'fatfish' ? 'medium' : 'fatfish')
  }
  return (
    <div className="app">
      {
        name === 'fatfish' ? 
          <Demo name={ name } /> : 
          <Demo name={ name } />
      }
      <button onClick={ onClick }>click</button>
    </div>
  )
}
ReactDOM.render(<App />, document.getElementById('app'))

我录制了一个简短的 gif,向你展示真相。

为什么?

尽管我们编写了两个 Demo 组件,并假设它们将分别被挂载和更新,但 React 认为它们是同一个组件,因此 componentDidMount 仅会执行一次。

如何解决?

但当我们想要编写两个相同的组件但传递不同的参数时,该怎么办呢?

是的,你应该为这两个组件添加不同的 key,这样 React 就会认为它们是不同的组件。componentDidMount 也将分别执行。

让我们试试

//...
// Pay attention here
name === 'fatfish' ? <Demo key="1" name={ name } /> : <Demo key="2" name={ name } />
//...

译自:https://javascript.plainenglish.io/my-boss-you-dont-know-react-at-all-f493970f1807

版权声明:本文内容由TeHub注册用户自发贡献,版权归原作者所有,TeHub社区不拥有其著作权,亦不承担相应法律责任。 如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

点赞(0)
收藏(0)
一个人玩
先找到想要的,然后出发

评论(0)

添加评论