2017-07-23 98 views
1

嗨,我是Redux的新手,我正在使用React和Redux來嘗試構建一個用於將文件(本例中的發票)拖放到其中的UI一部分UI,將它們呈現在列表中,然後能夠啓動彈出窗口來編輯與每張發票相關聯的元數據。拖放工作正常 - Redux每次刪除文件並更新列表時都會重新呈現視圖。但是,當我嘗試點擊每個發票的編輯按鈕時,商店正在更新,但我的popover組件中的道具不是。事實上,它看起來並不像任何重新呈現在所有發生的事情,當我試圖點擊編輯按鈕發票Redux不會重新渲染React組件,即使存儲已更新

App.js

import React from 'react' 
import AddInvoice from '../containers/AddInvoice' 
import CurrentInvoiceList from '../containers/CurrentInvoiceList' 
import ControlPopover from '../containers/ControlPopover' 

const App =() => (
    <div> 
    <AddInvoice /> 
    <CurrentInvoiceList /> 
    <ControlPopover /> 
    </div> 
) 

export default App 

集裝箱/ AddInvoice.js

import React from 'react' 
import { connect } from 'react-redux' 
import { addInvoice } from '../actions' 

const recipientDataDefaults = { 
    name: '', 
    surname: '', 
    address: '', 
    phone: '' 
}; 

const handleDragOver = event => { 
    event.stopPropagation(); 
    event.preventDefault(); 
    event.dataTransfer.dropEffect = 'copy'; 
}; 

const handleDragEnter = event => { 
    event.stopPropagation(); 
    event.preventDefault(); 
}; 

const handleDragLeave = event => { 
    event.stopPropagation(); 
    event.preventDefault();  
}; 

let AddInvoice = ({ dispatch }) => 
    const styles = {'minHeight': '200px', 'background': 'tomato'} 
    return (
    <div style={styles} 
     onDragEnter={handleDragEnter} 
     onDragLeave={handleDragLeave} 
     onDragOver={handleDragOver} 
     onDrop={event => { 
      event.stopPropagation(); 
      event.preventDefault(); 
      const data = event.dataTransfer; 
      const files = data.files; 

      const newInvoiceUploads = Object.keys(files) 
      .map(key => files[key]) 
      .map(file => { 
       const invoiceObject = {}; 
       invoiceObject.files = [file]; 
       invoiceObject.recipientData = Object.assign({}, recipientDataDefaults); 
       return invoiceObject; 
      }); 

      newInvoiceUploads.forEach(invoice => dispatch(addInvoice(invoice))) 

    }}> 
     Drag an invoice here to upload 
    </div> 
) 
} 
AddInvoice = connect()(AddInvoice) 

export default AddInvoice 

容器/ ControlPopover.js

import { connect } from 'react-redux' 
import { closePopoverWithoutSave } from '../actions' 
import Popover from '../components/Popover/Popover' 

const mapStateToProps = (state) => { 
    return { 
    isActive: !!state.isActive 
    } 
} 

const mapDispatchToProps = { 
    handleCancel: closePopoverWithoutSave 
} 


const ControlPopover = connect(
    mapStateToProps, 
    mapDispatchToProps 
)(Popover) 

export default ControlPopover 

容器/ CurrentInvoiceList.js

import { connect } from 'react-redux' 
import { showInvoiceEditPopover } from '../actions' 
import InvoiceList from '../components/InvoiceList/InvoiceList' 

const mapStateToProps = state => { 
    return { 
    invoices: state.invoices 
    } 
} 

const mapDispatchToProps = dispatch => ({ 
    handleEditInvoice: invoice => { 
    dispatch(showInvoiceEditPopover(invoice)) 
    } 
}) 

const CurrentInvoiceList = connect(
    mapStateToProps, 
    mapDispatchToProps 
)(InvoiceList) 

export default CurrentInvoiceList 

動作/ index.js

let nextInvoiceId = 0 
export const addInvoice = invoice => ({ 
    type: 'ADD_INVOICE', 
    id: nextInvoiceId++, 
    invoiceData: invoice 
}) 

export const showInvoiceEditPopover = invoice => ({ 
    type: 'SHOW_POPOVER', 
    invoice 
}) 

的酥料餅的減速器(組合中的應用,但這裏內聯爲了簡潔)減速器/ index.js

const popover = (state = {}, action) => { 
    switch (action.type) { 
    case 'SHOW_POPOVER': 
     const popoverState = {} 
     popoverState.isActive = true 
     popoverState.data = action.invoice 
     return popoverState 

    case 'CLOSE_POPOVER_WITHOUT_SAVING': 
     const inactiveState = {} 
     inactiveState.isActive = false 
     inactiveState.data = {} 
     return inactiveState; 
    default: 
     return state 
    } 
} 

export default popover 

組件/ InvoiceList.js

import React from 'react' 
import PropTypes from 'prop-types' 
import Invoice from '../Invoice/Invoice' 

const InvoiceList = ({ invoices, handleEditInvoice }) => { 

return (
    <div> 
    {invoices.map(invoice => 
     <Invoice 
     key={invoice.id} 
     invoice={invoice.invoiceData} 
     onClick={event => { 
      // here we invoke the action bound by the CurrentInvoiceList 
      // container 
      event.preventDefault() 
      handleEditInvoice(invoice) 
     }} 
     /> 
    )} 
    </div> 
) 
} 

InvoiceList.propTypes = { 
    invoices: PropTypes.arrayOf(PropTypes.shape({ 
    id: PropTypes.number.isRequired, 
    invoiceData: PropTypes.object 
    }).isRequired).isRequired, 
    handleEditInvoice: PropTypes.func.isRequired 
} 

export default InvoiceList 

組件/ Invoice.js

import React from 'react' 
import PropTypes from 'prop-types' 
import TextInput from '../TextInput/TextInput'; 
import Button from '../Button/Button'; 
import './invoice.css' 

const Invoice = ({ invoice, onClick }) => { 

const fileNames = invoice.files.map((file, index) => { 
    return (<div key={index} className="invoice__file-title-legend"> 
    {file.name}</div>); 
    }); 

return (
    <div className="invoice"> 
    <form className="invoice__form"> 
    <TextInput id="invoice__input-amount" placeholder="enter invoice amount" label="Invoice Amount" /> 
    <TextInput id="invoice__input-target" placeholder="enter payment target" label="Payment Target" /> 
    <Button value="Add recipient" onClick={onClick} /> // clicking this button updates the store but does NOT re-render. Why? 
    </form> 

    <div className="invoice__files">{fileNames}</div> 
</div> 
) 
} 

Invoice.propTypes = { 
    onClick: PropTypes.func.isRequired, 
    invoice: PropTypes.object 
} 

export default Invoice 

組件/酥料餅/ Popover.js

import React from 'react' 
import PropTypes from 'prop-types' 
import createModifiers  from '../../lib/createModifiers'; 
import './Popover.css'; 

const Popover = ({ handleCancel, isActive }) => { 
    console.log('rendering popover component') // does not get called when invoice edit button is pressed 
    const popoverModifiers = createModifiers('popover', { 
    'is-active': isActive 
    }) 

    return (
    <div className={popoverModifiers}> 
     <div className="popover__header"> 
     <button onClick={handleCancel}>x</button> 
     </div> 
     <div className="popover__content"> 
     Popover content 
     </div> 
    </div> 
) 
} 
Popover.propTypes = { 
    handleCancel: PropTypes.func.isRequired, 
    isActive: PropTypes.bool.isRequired 
} 

export default Popover 

最後的createModifiers代碼爲後人。這段代碼僅僅是生產基於在

const createModifiers = (element, modifiers) => { 
    const classList = Object.keys(modifiers) 
    .filter(key => modifiers[key]) 
    .map(modifier => `${element}--${modifier}`) 
    .concat(element) 
    .join(' ') 

    return classList 
} 

export default createModifiers 

過去,我知道這是一個大量的示例代碼,所以我試圖保持它簡短而集中地,同時給人一種狀態布爾值,一些BEM修改CSS類全面的應用視圖。任何幫助最受讚賞。

+0

Control PopPath的mapStateToProps是否被調用? –

+0

另外,ControlPopover中的mapDispatchToProps看起來很奇怪。我相信你需要修改它以返回像mapStateToProps這樣的函數。這可能會引發導致狀態更新不傳播的錯誤。 –

+0

mapStateToProps被調用,但我綁定了錯誤的對象屬性 – kojinkai

回答

0

我相信你的問題是你的​​3210函數格式不正確。

您需要返回具有方法的對象。這些方法將作爲道具給予您的連接組件。

實施例:

const mapDispatchToProps = (dispatch) => { 
    return { 
     doSomething: (arguments) => { 
      // here you can dispatch and use your arguments 
     } 
    }; 
} 

doSomething是將被提供給所連接的組件的支柱。

您的所有mapDispatchToProps函數都格式不正確。

邊注/意見 - TLDR

在未來,如果你有大量的代碼後,我相信它會更容易消化,如果片是連在一起的。

I.E.

// App.js 
const App =() => (
    <div> 
     <Header /> 
     <Body /> 
     <Footer /> 
    </div> 
); 

組件以下列順序顯示:header - > body - > footer。按順序爲他們提供代碼,將他們的動作,縮減器,表示和容器信息集中在一個塊中。

頁眉

// header.presentational.js ... 

// header.container.js ... (or where you mapStateToProps and connect) 

// header.actions.js ... 

// header.reducer.js ... 

身體......

頁腳...

我不知道,如果代碼是關於你的最終不同的,但你的mapStateToDispatch功能仍然是格式不正確。

改變了...

const mapDispatchToProps = dispatch => ({ 
    handleEditInvoice: invoice => { 
    dispatch(showInvoiceEditPopover(invoice)) 
    } 
}) 

要這樣:

const mapDispatchToProps = dispatch => ({ 
    return { 
    handleEditInvoice: invoice => { 
     dispatch(showInvoiceEditPopover(invoice)) 
    } 
    }; 
}) 
+0

感謝您的回答,以及對格式的反饋。 '''const mapDispatchToProps = { handleCancel:closePopoverWithoutSave }'''' 似乎格式不對,是的。直到popover被打開後,纔會調用它。在任何情況下修復此功能都不能解決問題。 Popover組件仍未呈現。 – kojinkai

+0

請你把代碼發佈到你的'createModifiers'。 –

+0

上面發佈了createModifiers。謝謝 – kojinkai

0

的問題是在集裝箱/ ControlPopover.js和mapStateToProps功能。 isActive屬性需要分配給state.popover.isActive

相關問題