2017-04-25 63 views
3

我正在通過React的待辦事項列表教程,並遇到以下錯誤,我花了相當一段時間,只是找不到錯誤..這裏有錯誤和對組件代碼,這是課程回購代碼(出現在此提交問題):React唯一的「鍵」錯誤

https://github.com/andrewjmead/react-course-todo-app/commit/0521f151705f78cb9f8d69262eb093f1431cb9ca

任何幫助非常讚賞。

警告:數組或迭代器中的每個子都應該有一個唯一的「key」屬性。檢查渲染方法TodoList。有關更多信息,請參見fb.me/react-warning-keys。

也有是在終端的錯誤,對於傳播操作的情況下,TOGGLE_TODO

return { 
...todo, // here 
completed: nextCompleted, 
completedAt: nextCompleted ? moment().unix() : undefined 
}; 

var React = require('react'); 
var { connect } = require('react-redux'); 
import Todo from 'Todo'; 
var TodoAPI = require('TodoAPI'); 

export var TodoList = React.createClass ({ 
    render: function() { 
     var { todos, showCompleted, searchText } = this.props; 
     var renderTodos =() => { 
      if(todos.length === 0) { 
       return (
        <p className="container__message">No tasks</p> 
       ); 
      } 
      return TodoAPI.filterTodos(todos, showCompleted, searchText).map((todo) => { 
       return (
        //add unique key prop to keep track of individual components 
        <Todo key={todo.id} {...todo} /> 
       ); 
      }); 
     }; 
     return (
      <div> 
       {renderTodos()} 
      </div> 
     ); 
    } 
}); 

export default connect(
    (state) => { 
     return state; 
    } 
)(TodoList); 

減速:

var uuid = require('uuid'); 
var moment = require('moment'); 

export var searchTextReducer = (state = '', action) => { 
    switch (action.type) { 
     case 'SET_SEARCH_TEXT': 
      return action.searchText; 
     default: 
      return state; 
    }; 
}; 

export var showCompletedReducer = (state = false, action) => { 
    switch (action.type) { 
     case 'TOGGLE_SHOW_COMPLETED': 
      return !state; 
     default: 
      return state; 
    };  
}; 

export var todosReducer = (state = [], action) => { 
    switch(action.type) { 
     case 'ADD_TODO': 
      return [ 
       ...state, 
       { 
        text: action.text, 
        id: uuid(), 
        completed: false, 
        createdAt: moment().unix(), 
        completedAt: undefined     
       } 
      ]; 
     case 'TOGGLE_TODO': 
      return state.map((todo) => { 
       if(todo.id === action.id) { 
        var nextCompleted = !todo.completed; 

        return { 
         ...todo, 
         completed: nextCompleted, 
         completedAt: nextCompleted ? moment().unix() : undefined 
        }; 
       } else { 
        return todo; 
       } 
      }); 
     case 'ADD_TODOS': 
      return [ 
       ...state, 
       ...action.todos 
      ]; 
     default: 
      return state; 
    } 
}; 


Webpack: 

var webpack = require('webpack'); 

module.exports = { 
    entry: [ 
    'script!jquery/dist/jquery.min.js', 
    'script!foundation-sites/dist/js/foundation.min.js', 
    './app/app.jsx' 
    ], 
    externals: { 
     jquery: 'jQuery' 
    }, 
    plugins: [ 
     new webpack.ProvidePlugin({ 
      '$': 'jquery', 
      'jQuery': 'jquery' 
     }) 
    ], 
    output: { 
    path: __dirname, 
    filename: './public/bundle.js' 
    }, 
    resolve: { 
    root: __dirname, 
    modulesDirectories: [ 
     'node_modules', 
     './app/components', 
     './app/api' 
    ], 
    alias: { 
     applicationStyles: 'app/styles/app.scss', 
     actions: 'app/actions/actions.jsx', 
     reducers: 'app/reducers/reducers.jsx', 
     configureStore: 'app/store/configureStore.jsx' 
    }, 
    extensions: ['', '.js', '.jsx'] 
    }, 
    module: { 
    loaders: [ 
     { 
     loader: 'babel-loader', 
     query: { 
      presets: ['react', 'es2015'] 
     }, 
     test: /\.jsx?$/, 
     exclude: /(node_modules|bower_components)/ 
     } 
    ] 
    }, 
    devtool: 'cheap-module-eval-source-map' 
}; 

回答

3

節點的UUID已過時,點擊這裏:https://www.npmjs.com/package/uuid

您可以通過安裝UUID更新您的package.json,並看看是否有幫助:

NPM安裝UUID

只是不要忘記更新var uuid = require('node-uuid'); var uuid = require('uuid');在你的其他文件中。

P.S.當你運行一個webpack時,你的終端是否有錯誤?

+2

你能分享你的reducer/actions文件嗎? – Joe

+0

那裏我編輯了帖子 – Smithy

+1

它似乎是你的webpack中缺少babel stage-0,如果你得到了擴散運算符錯誤,請嘗試安裝npm install --save-dev babel-preset-stage-0 – Joe

2

我敢打賭todo.idundefined,因此不是唯一的。你能在你的例子中包含todos嗎?

+0

請檢查bntzio的帖子上的答案整個代碼是包含在鏈接 – Smithy

2

您可以添加index參數去你map功能,該指數傳遞到您的Todo組件:

export var TodoList = React.createClass ({ 
    render: function() { 
     var { todos, showCompleted, searchText } = this.props; 
     var renderTodos =() => { 
      if(todos.length === 0) { 
       return (
        <p className="container__message">No tasks</p> 
       ); 
      } 
      return TodoAPI.filterTodos(todos, showCompleted, searchText).map((todo, index) => { // here <==== 
       return (
        //add unique key prop to keep track of individual components 
        <Todo key={`key-${index}`} {...todo} /> 
       ); 
      }); 
     }; 
     return (
      <div> 
       {renderTodos()} 
      </div> 
     ); 
    } 
}); 
+0

小心這種做法;如果你用不同的'todos'重新渲染父項,可能會導致問題,因爲密鑰會被重用。 –

+0

好的,我會記住這一點。 只有一個問題:如果孩子們改變了鑰匙的重複使用會導致問題的方式?因爲舊的孩子將被刪除,他們的鑰匙與他們(嗯,我認爲這是怎麼回事) –

+0

謝謝我已經嘗試過,但我仍然有同樣的錯誤... – Smithy

3

在反應,當你渲染多個分量相等(在你的情況下,待辦事項),您需要爲每個人添加一個唯一的密鑰,這是因爲React需要知道他們將如何在虛擬世界中得到處理。

你可以做各種事情來解決這個問題:每次循環結束,然後設置

  1. 在for循環中,創建一個索引變量,並通過1增加它是爲每個渲染分量的關鍵。

  2. 如果你從api中獲取你的todos,爲每個todo設置一個id並將它用作你的組件密鑰。

  3. 使用隨機數生成器在每個待辦事項上設置唯一密鑰。

的最佳方法是#2,#3,我看到你的情況,你正在試圖做的#2(設置由待辦事項ID的關鍵),但我認爲這是不確定的,檢查它。

另一種解決方案是在每個渲染的組件/待辦事項上使用uuid

爲此,您可以安裝node-uuid

運行:npm i --save node-uuid

然後做你的文件導入:import uuid from 'node-uuid'const uuid = require('node-uuid')

現在改變你的代碼是這樣的:

return TodoAPI.filterTodos(todos, showCompleted, searchText).map((todo) => { 
    return (
    //add unique key prop to keep track of individual components 
    <Todo key={uuid()} {...todo} /> 
); 
}); 

然後你去好。

+0

是的,我在父組件(TodoApp ),我已經嘗試了你的解決方案,但是我仍然得到相同的錯誤信息。即使我克隆他的代碼並且弄亂了我的錯誤,我的代碼仍然與教師的日期一致。所以這是相同的代碼,直到這個提交:https://github.com/andrewjmead/react-course-todo-app/commit/0521f151705f78cb9f8d69262eb093f1431cb9ca – Smithy