• 1000 * Вот ссылка на видео о том, что я описываю:
https://drive.google.com/file/d/1qTKTdItvK4jhdHQUZ19rPdWUSRmc8r2E/view?usp=sharing Процесс должен быть:
- Я вношу изменения и отправляю изменение веб-сокета
- веб-сокет генерирует данные, которые правильно представляют новые данные
- состояние обновления страницы для отражения новых данных
однако шаг 3 никогда не обновляет штат. Мне нужно принудительно выполнить обновление, щелкнув в другом месте, чтобы данные появились, поэтому я знаю, что данные есть. Кроме того, по какой-то причине ни componentWillReceiveProps, ни getDerivedStateFromProps, похоже, не срабатывают.
Вот часть моего кода:
Мой компонент
class RiskSettings extends PureComponent {
constructor(props) {
super(props)
this.state = {
risk_setting: this.props.risk_setting,
showConfigureDisplayModal: false,
displayOptions: ['firm', 'trader', 'marginlimit'],
maxAmountOfOptions: 10,
entryToEdit: {
item: '',
option: '',
value: ''
}
}
}
// componentWillReceiveProps(nextProps) {
// console.log('test')
// if (nextProps !== this.props) {
// this.setState({
// risk_setting: nextProps.risk_setting
// })
// }
// }
// static getDerivedStateFromProps(nextProps, prevState) {
// if (nextProps.risk_setting !== prevState.risk_setting) {
// return {
// risk_setting: nextProps.risk_setting
// }
// }
//
// return null
// }
handleCloseConfigureDisplayModal = () => {
this.setState({
showConfigureDisplayModal: false
})
}
handleShowConfigureDisplayModal = () => {
this.setState({
showConfigureDisplayModal: true
})
}
parseKeysIntoArray = object => {
if (Object.keys(object).length > 0) {
return Object.keys(object)
} else {
return []
}
}
handleModifyDisplayOptions = key => {
const newOptions = this.state.displayOptions
if (newOptions.includes(key)) {
const index = newOptions.indexOf(key)
newOptions.splice(index, 1)
} else {
if (newOptions.length < this.state.maxAmountOfOptions) {
newOptions.push(key)
}
}
this.forceUpdate()
}
handleResetDisplayOptions = () => {
this.setState({
displayOptions: ['firm', 'trader', 'marginlimit'],
})
}
handleSelectEntryToEdit = (option, item, value) => {
this.setState({
entryToEdit: {
option: option,
item: item,
value: value,
}
})
}
handleStopEditingEntry = () => {
this.setState({
entryToEdit: {
option: '',
item: '',
value: ''
}
})
}
handleEditEntry = (e, item, option) => {
this.setState({
entryToEdit: {
...this.state.entryToEdit,
value: e.target.value
}
})
}
handleSaveEditedEntry = () => {
const { option, value, item } = this.state.entryToEdit
const new_risk_setting = this.state.risk_setting
const message = {
type: 'account_update',
firm: item.firm,
trader: item.trader,
}
// new_risk_setting[item.trader][option] = value
message[option] = value
this.props.websocket.send(JSON.stringify(message))
this.handleStopEditingEntry()
}
/****************************************************************************/
renderLoading = () => (
<Row noGutters className='app-spinner'>
<Spinner animation='border' className='common-grey-spinner' />
</Row>
)
renderTable = props => {
const { displayOptions } = this.state
const risk_setting = this.props.risk_setting
const arrayOfKeys = this.parseKeysIntoArray(risk_setting)
let body
if (arrayOfKeys.length > 0) {
const arrayOfValues = Object.values(risk_setting)
body = arrayOfValues.map((item, index) => this.renderTableItem(item, index))
} else {
body = this.renderLoading()
}
let tableHeaders
if (displayOptions.length > 0) {
tableHeaders = displayOptions.map((option, index) => this.renderTableHeader(option, index))
}
return (
<Table responsive bordered className='submissions-table'>
<thead>
<tr>
{tableHeaders}
</tr>
</thead>
<tbody>
{body}
</tbody>
</Table>
)
}
renderTableHeader = (option, index) => (
<th key={'tableHeader - index: ' + index} className='table-header-cell'>{option}</th>
)
renderTableItem = (item, index) => {
const { displayOptions } = this.state
let tableContents
if (displayOptions.length > 0) {
tableContents = displayOptions.map((option, index) => this.renderMatchingTableItem(item, option, index))
}
return (
<tr key={'tableItem - index: ' + index} className='table-cell'>
{tableContents}
</tr>
)
}
renderMatchingTableItem = (item, option, index) => {
const { entryToEdit } = this.state
let content
if (option == 'trader' || option == 'firm') {
content = item[option]
} else {
if (entryToEdit.item.trader === item.trader && entryToEdit.option === option) {
content = (
<Row noGutters className='table-cell-row'>
<FormControl
onChange={e => this.handleEditEntry(e, item, option)}
value={entryToEdit.value}
className='table-cell-formControl'/>
<div>
<AiOutlineClose
onClick={this.handleStopEditingEntry}
className='individual-form-icon' />
<AiOutlineSave
onClick={() => this.handleSaveEditedEntry()}
className='individual-form-icon' />
</div>
</Row>
)
} else {
content = (
<Row noGutters className='table-cell-row'>
{item[option]}
<AiOutlineEdit
className='individual-form-icon'
onClick={() => this.handleSelectEntryToEdit(option, item, item[option])} />
</Row>
)
}
}
return (
<td
key={'matchingTableItem - index: ' + index}
className='matching-table-item'>
{content}
</td>
)
}
renderConfigureDisplayButton = () => {
return (
<Button
onClick={this.handleShowConfigureDisplayModal}
className='teal-button' size='sm'>
Configure Display
</Button>
)
}
renderConfigureDisplayModal = () => {
const { showConfigureDisplayModal, risk_setting, maxAmountOfOptions } = this.state
const arrayOfKeys = this.parseKeysIntoArray(risk_setting)
let content
if (arrayOfKeys.length > 0) {
const values = risk_setting[arrayOfKeys[0]]
const arrayOfKeysFromValues = Object.keys(values)
content = arrayOfKeysFromValues.map(key => this.renderKeyCheckbox(key))
}
return (
<Modal
centered
className='common-modal'
show={showConfigureDisplayModal}
onHide={this.handleCloseConfigureDisplayModal}>
<Modal.Header className='common-modal-header' closeButton>
Risk Settings Display Options
</Modal.Header>
<Modal.Body>
<div className='max-amount-of-options'>
You can select up to {maxAmountOfOptions} options
</div>
<Form>
<Row noGutters className='risk-settings-content-row'>
{content}
</Row>
</Form>
</Modal.Body>
<Modal.Footer>
<AiOutlineRedo
onClick={this.handleResetDisplayOptions}
className='individual-form-icon' />
<Button
onClick={this.handleCloseConfigureDisplayModal}
className='teal-button' size='sm'>
Save
</Button>
</Modal.Footer>
</Modal>
)
}
renderKeyCheckbox = key => {
const { displayOptions } = this.state
return (
<Form.Check
checked={displayOptions.includes(key) ? true : false}
onChange={() => this.handleModifyDisplayOptions(key)}
className='risk-settings-key-checkbox'
key={key} name={key} size='sm' label={key} />
)
}
render() {
return (
<Container fluid className='forms-container'>
{this.renderConfigureDisplayModal()}
<Row noGutters className='forms-header'>
<h4>Risk Settings</h4>
{this.renderConfigureDisplayButton()}
</Row>
<div className='forms-table-box'>
{this.renderTable()}
</div>
</Container>
)
}
}
export default RiskSettings
Мой eventChannel
function createEventChannel(mySocket, userData) {
return eventChannel(emitter => {
mySocket.onopen = () => {
console.log('opening connection...')
const challenge = JSON.stringify({ type: 'challenge' })
mySocket.send(challenge)
}
mySocket.onmessage = e => {
const message = JSON.parse(e.data) || ''
if (message) {
// console.log('message: ', message)
if (message.type === 'challenge' && message.result === 'OK') {
const encrypt = new JSEncrypt()
encrypt.setPublicKey(message.key)
const encryptedPass = encrypt.encrypt(userData.pass)
const loginMessage = JSON.stringify({
type: 'login',
userid: userData.userid,
pass: encryptedPass
})
mySocket.send(loginMessage)
} else if (message.type === 'current_risk') {
} else if (message.type === 'account_update') {
// if (message.result === 'OK') {
// // console.log(message)
// return emitter({ type: 'INJECT_TRADER', message })
// } else {
// toast.error(message.result)
// }
} else if (message.type === 'risk_setting') {
return emitter({ type: 'INJECT_TRADER', message })
} else if (message.type === 'login' && message.result === 'OK') {
return emitter({ type: 'LOGIN_SUCCESS', userData })
} else if (message.type === 'login' && message.result !== 'OK') {
toast.error(message.result)
return emitter({ type: 'LOGIN_ERROR' })
}
}
}
return () => {
mySocket.close()
console.log('socket off')
}
})
}
Мой редуктор
import { history } from '../../configureStore';
import * as CONSTANTS from '../constants/admin';
const initialState = {
risk_setting: {},
}
export default (state = initialState, action) => {
switch (action.type) {
case CONSTANTS.INJECT_TRADER:
// console.log(action.message)
const new_risk_setting = state.risk_setting
new_risk_setting[action.message.trader] = action.message
return {
...state,
risk_setting: new_risk_setting
}
// case CONSTANTS.UPDATE_RISK_SETTINGS_FIELD:
// const updated_risk_settings = state.risk_setting
// update_risk_settings[action.data.trader] = action.data
// return {
// ...state,
// risk_setting: new_risk_setting
// }
default:
return state
}
}