【问题标题】:Built React App works fine but same App in Dev mode (npm start) works not properly构建的 React 应用程序工作正常,但开发模式下的相同应用程序(npm start)不能正常工作
【发布时间】:2020-12-20 20:07:53
【问题描述】:

我是 react 和前端应用程序的初学者,所以我决定向this youtube react tutorial 学习。我对html、js和css有一些了解。

链接导致我遇到问题的课程(在 React 中练习 state)。问题是:

onChange 分配给复选框的函数,当通过npm start 启动应用程序时,正在执行... 奇怪。如果我这样做,相同的功能会按预期工作:npm run buildserve -s build

在教程中一切正常,我检查了我的代码,它与教程中的 100% 相同。我还将我的源代码发送给了我的一位同事,并且......一切都按照教程进行(我们都安装了 Windows 10)。

当尝试通过serve -s build 启动应用程序时,我鼓励我在this question 的帮助下解决了另一个问题(此系统上禁用了脚本的执行 - 我已经运行了Set-ExecutionPolicy RemoteSigned在 windows powerShell 中)。

我也尝试过删除 node_modules 并运行 npm install

App.js(我已经删除了 App.js 的导入和导出):

class App extends React.Component {
  constructor() {
    super()
    this.state = {
      todos: checklist
    }
    this.handleChange = this.handleChange.bind(this)
  } 
  handleChange(id) {
    console.log("debug1", id)
    this.setState(prevState => {
      const updatedToDos = prevState.todos.map(todo => {
        if (todo.id === id) {
          console.log(todo.id, id, todo.isChecked)
          todo.isChecked = !todo.isChecked
          console.log(todo.id, id, todo.isChecked)
        }
        console.log(todo)
        return todo
      })
      console.log(updatedToDos)
      return {
        todos: updatedToDos
      }
    })
  }
  render() {
    const todoChecklist = this.state.todos.map(item => <ToDoItm key={item.id} item={item} 
      handleChange={this.handleChange.bind(this)}/>)
    return(
      <div>
        {todoChecklist}
      </div>
    )
  }
}

checklist.js 是包含 TodoItems

集合的 json 文件

ToDoItm(也删除了导出和导入):

function ToDoItm(props) {
    return (
        <div className="todo-item">
            <h1>{props.item.line}</h1>
            <input 
                type="checkbox" 
                checked={props.item.isChecked}
                onChange={() => props.handleChange(props.item.id)} 
            />
        </div>
    )
}

附言。 代理 奇怪 我的意思是 - 当我点击第一个复选框时会发生这种情况:

【问题讨论】:

    标签: javascript node.js reactjs npm-start


    【解决方案1】:

    所以基本上在这里你正在改变反应状态的原始对象,这不是正确的做法你需要做的是在这个 todos 数组中克隆这些对象。你可以按照下面的代码进行操作。而且这个 handleChange 整体没有优化它可能是以更有效的方式编写,但对于初学者来说没关系,请阅读此https://daveceddia.com/why-not-modify-react-state-directly/

    import React from 'react';
    
    function ToDoItm(props) {
      return (
        <div className="todo-item">
          <h1>{props.item.line}</h1>
          <input
            type="checkbox"
            checked={props.item.isChecked}
            onChange={() => props.handleChange(props.item.id)}
          />
        </div>
      )
    }
    
    class App extends React.Component {
      constructor() {
        super()
        this.state = {
          todos: [{ id: 1, line: '1' }, { id: 2, line: '2' }, { id: 3, line: '3' }, { id: 4, line: '4' }]
        }
        this.handleChange = this.handleChange.bind(this)
      }
      handleChange(id) {
        console.log("debug1", id)
        this.setState(prevState => {
          const updatedToDos = prevState.todos.map(todo => {
            // change that i made to clone object inside todos array
            const newtodo = Object.assign({}, todo);
            if (newtodo.id === id) {
              console.log(newtodo.id, id, newtodo.isChecked)
              newtodo.isChecked = !newtodo.isChecked
              console.log(newtodo.id, id, newtodo.isChecked)
            }
            console.log(todo)
            return newtodo
          })
          console.log(updatedToDos)
          return {
            todos: updatedToDos
          }
        })
      }
      render() {
        const todoChecklist = this.state.todos.map(item => <ToDoItm key={item.id} item={item}
          handleChange={this.handleChange.bind(this)} />)
        return (
          <div>
            {todoChecklist}
          </div>
        )
      }
    }
    
    export default App;
    

    您会看到我如何在 handleChange 函数中克隆这些对象并返回一个没有引用原始 React 状态的 newObject,您可以使用不同的方法来克隆内部对象。

    检查您的主应用程序是否未环绕严格模式

    ReactDOM.render(
      <React.StrictMode>
        <App />
      </React.StrictMode>,
      document.getElementById('root')
    );  
    

    StrictMode 两次调用您应用的构造函数和其他方法(仅在开发中)以确保没有副作用。尝试删除 StrictMode 看看是否有帮助。

    【讨论】:

    • 是的,它可以工作,但问题并没有完全解决,因为这种方法还给我这种奇怪的效果,即只单击一次就执行此地图功能两次 - 见截图 - 这只是在第一个复选框上单击一次。使用npm run build 构建应用程序时,控制台仅显示 4 个对象的日志。
    • 尝试删除 StrictMode(如果存在)
    • 是的,正如我在回答中所说,我设法通过删除 React.StrictMode 组件包装器来解决这个问题
    【解决方案2】:

    所以,我在this blog post 上找到了答案。

    事实证明,当您使用 npx create-react-app 创建 react 应用程序时,App.js 组件在使用它调用 ReactDOM.Render 时 - 被 React.StrictMode 包裹

    ReactDOM.render(
      <React.StrictMode>
        <App />,
      </React.StrictMode>,
      document.getElementById('root')
    );
    

    关于这个包装器的发行说明说:

    React.StrictMode 是一个包装器,可帮助为异步渲染准备应用程序

    React.StrictMode 是两次重新渲染应用程序的根源,因此是问题的根源。

    在博文中,您可以阅读:

    我们从 React.StrictMode 的使用中获得的一个好处是,它可以帮助我们检测渲染阶段生命周期中的意外副作用。

    但生命周期超出了我目前对 React 的了解。

    你也可以阅读React.StrictMode documentation

    删除这个包装器解决了这个问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-11-01
      • 2021-02-25
      • 1970-01-01
      • 1970-01-01
      • 2018-09-08
      • 1970-01-01
      • 2021-04-09
      相关资源
      最近更新 更多