我正在构建多用户语言词典,并且一直坚持按ID编辑单词。我正在使用 React-Redux-NodeJS堆栈。我想我不太了解redux,尤其是 actions和reducers 。因此,如果您给我一些指导,我将非常高兴。以下是我的代码文件。
Word API (Node JS)
// @route Put api/words/:id
// @desc Update a word by id
// @access Private
router.put(
'/:id',
passport.authenticate('jwt', { session: false }),
(req, res) => {
const { errors, isValid } = validateWordInput(req.body);
// Check validation
if (!isValid) {
// Return any errors
return res.status(400).json(errors);
}
Profile.findOne({ user: req.user.id }).then(profile => {
Word.findById(req.params.id)
.then(word => {
// Check for word owner
if (word.user.toString() !== req.user.id) {
return res
.status(401)
.json({ notauthorized: 'User not authorized' });
}
const wordID = req.params.id;
const wordInput = req.body;
// Update
Word.findByIdAndUpdate(
{ _id: wordID },
{ $set: wordInput },
{ returnOriginal: false },
(err, word) => {
if (err) {
console.log(err);
}
}
).then(word => res.json(word));
})
.catch(err => res.status(404).json({ nowordfound: 'No word found' }));
});
}
);
编辑单词形式(反应)
import React, { Component } from 'react';
import { Link, withRouter } from 'react-router-dom';
import TextFieldGroup from '../common/TextFieldGroup';
import SelectListGroup from '../common/SelectListGroup';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { addWord, updateWord } from '../../actions/wordActions';
import isEmpty from '../../validation/is-empty';
class EditWord extends Component {
constructor(props) {
super(props);
this.state = {
ugrWordCyr: '',
rusTranslation: '',
example: '',
exampleTranslation: '',
origin: '',
sphere: '',
see: '',
lexis: '',
grammar: '',
partOfSpeech: '',
style: '',
errors: {}
};
this.onChange = this.onChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.onCheck = this.onCheck.bind(this);
}
componentWillReceiveProps(nextProps) {
if (nextProps.errors) {
this.setState({ errors: nextProps.errors });
}
if (nextProps.words.words) {
const words = nextProps.words.words;
// if profile field does not exist make empty string
words.ugrwordsCyr = !isEmpty(words.ugrwordsCyr) ? words.ugrwordsCyr : '';
words.rusTranslation = !isEmpty(words.rusTranslation)
? words.rusTranslation
: '';
words.example = !isEmpty(words.example) ? words.example : '';
words.exampleTranslation = !isEmpty(words.exampleTranslation)
? words.exampleTranslation
: '';
words.origin = !isEmpty(words.origin) ? words.origin : '';
words.sphere = !isEmpty(words.sphere) ? words.sphere : '';
words.see = !isEmpty(words.see) ? words.see : {};
words.lexis = !isEmpty(words.lexis) ? words.lexis : {};
words.grammar = !isEmpty(words.grammar) ? words.grammar : {};
words.see = !isEmpty(words.see) ? words.see : {};
words.style = !isEmpty(words.style) ? words.style : {};
// Set component fields state
this.setState({
ugrWordCyr: words.ugrWordCyr,
rusTranslation: words.rusTranslation,
example: words.example,
exampleTranslation: words.exampleTranslation,
origin: words.origin,
lexis: words.lexis,
grammar: words.grammar,
see: words.see,
partOfSpeech: words.partOfSpeech
});
}
}
onSubmit(e) {
e.preventDefault();
const wordData = {
ugrWordCyr: this.state.ugrWordCyr,
rusTranslation: this.state.rusTranslation,
example: this.state.example,
exampleTranslation: this.state.exampleTranslation,
origin: this.state.origin,
sphere: this.state.sphere,
see: this.state.see,
lexis: this.state.lexis,
grammar: this.state.grammar,
partOfSpeech: this.state.partOfSpeech,
style: this.state.style
};
this.props.updateWord(wordData, this.props.history);
}
onChange(e) {
this.setState({ [e.target.name]: e.target.value });
}
onCheck(e) {
this.setState({
current: !this.state.current
});
}
render() {
const { errors } = this.state;
const sphereOptions = [
{ label: 'Выберите сферу употребления слова', value: 0 },
{ label: 'Анатомия', value: 'Анатомия' },
{ label: 'Археология', value: 'Археология' },
{ label: 'Архитектура', value: 'Архитектура' },
{ label: 'Астрономия', value: 'Астрономия' },
{ label: 'Биология', value: 'Биология' },
{ label: 'Ботаника', value: 'Ботаника' },
{ label: 'Бухгалтерия', value: 'Бухгалтерия' },
{ label: 'Ветеренария', value: 'Ветеренария' },
{ label: 'География', value: 'География' },
{ label: 'Диалектизм', value: 'Диалектизм' },
{ label: 'Дипломатический термин', value: 'Дипломатический термин' },
{ label: 'Железнодорожное дело', value: 'Железнодорожное дело' },
{ label: 'Зоология', value: 'Зоология' },
{ label: 'Исторический термин', value: 'Исторический термин' },
{ label: 'Кулинария', value: 'Кулинария' },
{ label: 'Лингвистика', value: 'Лингвистика' },
{ label: 'Математика', value: 'Математика' },
{ label: 'Медицина', value: 'Медицина' },
{ label: 'Религия', value: 'Религия' },
{ label: 'Физкультура и спорт', value: 'Физкультура и спорт' },
{ label: 'Сельзкое хозяйство', value: 'Сельзкое хозяйство' },
{ label: 'Фармацептический термин', value: 'Фармацептический термин' },
{ label: 'Физика', value: 'Физика' },
{ label: 'Физиология', value: 'Физиология' },
{ label: 'Фольклор', value: 'Фольклор' },
{ label: 'Химия', value: 'Химия' },
{ label: 'Экономика', value: 'Экономика' },
{ label: 'Этнография', value: 'Этнография' },
{ label: 'Юридический термин', value: 'Юридический термин' }
];
const originOptions = [
{ label: 'Выберите вариант происхождения слова', value: 0 },
{ label: 'Арабское слово', value: 'Арабское слово' },
{ label: 'Китайское слово', value: 'Китайское слово' },
{ label: 'Русское слово', value: 'Русское слово' },
{ label: 'Монгольский язык', value: 'Монгольский язык' },
{ label: 'Персидское слово', value: 'Персидское слово' },
{ label: 'Уйгурское слово', value: 'Уйгурское слово' },
{ label: 'Китайско-Уйгурское слово', value: 'Китайско-Уйгурское слово' },
{
label: 'Монгольско-Уйгурское слово',
value: 'Могольско-Уйгурское слово'
},
{ label: 'Русско-уйгурское слово', value: 'Русско-уйгурское слово' },
{ label: 'Арабско-Уйгурское слово', value: 'Арабско-Уйгурское слово' },
{ label: 'Персидско-Уйгурское слово', value: 'Персидско-Уйгурское слово' }
];
const lexisOptions = [
{ label: 'Выберите лексику слова', value: 0 },
{ label: 'В переносном значении', value: 'В переносном значении' },
{ label: 'Малоупотребительно', value: 'Малоупотребительно' },
{ label: 'Поговорка', value: 'Поговорка' },
{ label: 'Пословица', value: 'Пословица' },
{ label: 'В разных значениях', value: 'В разных значениях' },
{ label: 'В прямом значении', value: 'В прямом значении' }
];
const styleOptions = [
{ label: 'Выберите стиль слова', value: 0 },
{ label: 'Бранное слово', value: 'Бранное слово' },
{ label: 'Поэтическое слово', value: 'Поэтическое слово' },
{ label: 'Разговорное слово', value: 'Разговорное слово' },
{ label: 'Книжный стиль', value: 'Книжный стиль' },
{ label: 'Неодобрительно', value: 'Неодобрительно' },
{ label: 'В ироничном смысле', value: 'В ироничном смысле' }
];
const partOfSpeechOptions = [
{ label: 'Выберите часть речи к которому принадлежит слово', value: 0 },
{ label: 'Вводное слово', value: 'Вводное слово' },
{
label: 'Вопросительное местоимение',
value: 'Вопросительное местоимение'
},
{ label: 'Вопросительная частица', value: 'Вопросительная частица' },
{ label: 'Глагол', value: 'Глагол' },
{
label: 'Количественное числительное',
value: 'Количественное числительное'
},
{
label: 'Существительное',
value: 'Существительное'
},
{
label: 'Порядковое числительное',
value: 'Порядковое числительное'
},
{
label: 'Междометие',
value: 'Междометие'
},
{
label: 'Звукоподражание',
value: 'Звукоподражание'
},
{
label: 'Личное местоимение',
value: 'Личное местоимение'
},
{
label: 'Местоимение',
value: 'Местоимение'
},
{
label: 'Отрицательная частица',
value: 'Отрицательная частица'
},
{
label: 'Имя прилагательное',
value: 'Имя прилагательное'
},
{
label: 'Причастие',
value: 'Причастие'
},
{
label: 'Разделительный союз',
value: 'Разделительный союз'
},
{
label: 'Собирательное существительное',
value: 'Собирательное существительное'
},
{
label: 'Соединительный союз',
value: 'Соединительный союз'
},
{
label: 'Указательное местоимение',
value: 'Указательное местоимение'
},
{
label: 'Число',
value: 'Число'
},
{
label: 'Усилительная частица',
value: 'Усилительная частица'
},
{
label: 'Утвердительная частица',
value: 'Утвердительная частица'
}
];
const grammarOptions = [
{ label: 'Выберите грамматику слова', value: 0 },
{ label: 'Имя действия', value: 'Имя действия' },
{ label: 'Лицо глагола', value: 'Лицо глагола' },
{ label: 'Взаимный залог', value: 'Взаимный залог' },
{ label: 'Возвратный залог', value: 'Возвратный залог' },
{ label: 'Грамматика', value: 'Грамматика' },
{ label: 'Дательный падеж', value: 'Дательный падеж' },
{ label: 'Деепречастие', value: 'Деепречастие' },
{ label: 'Единственное число', value: 'Единственное число' },
{ label: 'Множественное число', value: 'Множественное число' },
{ label: 'Многократный вид глагола', value: 'Многократный вид глагола' },
{ label: 'Однократный вид глагола', value: 'Однократный вид глагола' },
{ label: 'Направительный падеж', value: 'Направительный падеж' },
{ label: 'Сравнительная степень', value: 'Сравнительная степень' },
{ label: 'Страдательный залог', value: 'Страдательный залог' },
{ label: 'Родительный падеж', value: 'Родительный падеж' },
{ label: 'Уменьшительная форма', value: 'Уменьшительная форма' }
];
return (
<div className="add-word">
<div className="container">
<div className="row">
<div className="col-md-8 m-auto">
<Link to="/my-words" className="btn btn-light">
Go Back
</Link>
<h1 className="display-4 text-center">Edit Word</h1>
<form onSubmit={this.onSubmit}>
<TextFieldGroup
placeholder="Бала"
info="Введите слово на уйгурском"
name="ugrWordCyr"
value={this.state.ugrWordCyr}
onChange={this.onChange}
error={errors.ugrWordCyr}
/>
<TextFieldGroup
placeholder="Ребенок"
info="Введите слово на русском"
name="rusTranslation"
value={this.state.rusTranslation}
onChange={this.onChange}
error={errors.rusTranslation}
/>
<div className="form-check mb-form">
<input
type="checkbox"
className="form-check-input"
name="see"
value={this.state.see}
onChange={this.onCheck}
id="see"
/>
<label htmlFor="see">Смотри</label>
</div>
<TextFieldGroup
placeholder=""
info="Введите пример предложения на уйгурском"
name="example"
value={this.state.example}
onChange={this.onChange}
error={errors.example}
/>
<TextFieldGroup
placeholder=""
info="Введите перевод примерного предложения на русском"
name="exampleTranslation"
value={this.state.exampleTranslation}
onChange={this.onChange}
error={errors.exampleTranslation}
/>
<h6>Происхождение слова</h6>
<SelectListGroup
placeholder="Арабское"
name="origin"
value={this.state.origin}
onChange={this.onChange}
error={errors.origin}
options={originOptions}
/>
<h6>Сфера употребления слова</h6>
<SelectListGroup
placeholder="Физика"
name="sphere"
value={this.state.sphere}
onChange={this.onChange}
error={errors.sphere}
options={sphereOptions}
/>
<h6>Лексика слова</h6>
<SelectListGroup
placeholder=""
name="lexis"
value={this.state.lexis}
onChange={this.onChange}
error={errors.lexis}
options={lexisOptions}
/>
<h6>Стиль слова</h6>
<SelectListGroup
placeholder=""
name="style"
value={this.state.style}
onChange={this.onChange}
error={errors.style}
options={styleOptions}
/>
<h6>Часть речи</h6>
<SelectListGroup
placeholder=""
name="partOfSpeech"
value={this.state.partOfSpeech}
onChange={this.onChange}
error={errors.partOfSpeech}
options={partOfSpeechOptions}
/>
<h6>Грамматика слова</h6>
<SelectListGroup
placeholder=""
name="grammar"
value={this.state.grammar}
onChange={this.onChange}
error={errors.grammar}
options={grammarOptions}
/>
<input
type="submit"
value="submit"
className="btn btn-info btn-block mt-4"
/>
</form>
</div>
</div>
</div>
</div>
);
}
}
EditWord.propTypes = {
addWord: PropTypes.func.isRequired,
updateWord: PropTypes.func.isRequired,
errors: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
errors: state.errors,
word: state.words
});
export default connect(
mapStateToProps,
{ addWord, updateWord }
)(withRouter(EditWord));
文字动作(Redux)
import axios from 'axios';
import { GET_ERRORS, GET_WORDS_BY_USER, ADD_WORD, UPDATE_WORD } from './types';
export const addWord = (wordData, history) => dispatch => {
axios
.post('/api/words', wordData)
.then(res => {
dispatch({
type: ADD_WORD,
payload: res.data
});
history.push('/dashboard');
})
.catch(err =>
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
);
};
export const getWordsByUser = () => dispatch => {
axios
.get('/api/words')
.then(res =>
dispatch({
type: GET_WORDS_BY_USER,
payload: res.data
})
)
.catch(err =>
dispatch({
type: GET_WORDS_BY_USER,
payload: null
})
);
};
**export const updateWord = id => dispatch => {
axios
.get('/api/words/:id')
.then(res =>
dispatch({
type: UPDATE_WORD,
payload: res.data
})
)
.catch(err =>
dispatch({
type: UPDATE_WORD,
payload: null
})
);
};**
Word Reducer
import { GET_WORDS_BY_USER, ADD_WORD, UPDATE_WORD } from '../actions/types';
const initialState = {
words: [],
word: {},
loading: false
};
export default function(state = initialState, action) {
switch (action.type) {
case ADD_WORD:
return {
...state,
words: [action.payload, ...state.words]
};
case GET_WORDS_BY_USER:
return {
...state,
words: action.payload,
loading: false
};
case UPDATE_WORD:
return {
...state,
word: action.payload
};
default:
return state;
}
}