现在我正在使用 react redux store 和 local store 构建一个应用程序。 我有两个组件“tweetTable_Comp”和“likeButton_Comp”。 redux store 拥有通过 API 获取的所有推文记录“tweets”,tweetTable_Comp 具有本地状态“filteredTweets”,以便稍后添加过滤功能并仅显示选定类型的推文。
并且每条推文都有喜欢的UserIds。 tweetTable_Comp 将喜欢的用户 ID 作为道具传递给 likeButton_Comp,以便它可以根据您是否已经喜欢这条推文来添加不同的样式。
这里的问题是,当用户按下类似按钮时,更改 redux 存储中的“tweets[indexNum].likingUserIds”也会影响本地状态“filteredTweets[indexNum].likingUserIds”。
我打算一一更改 redux 信息和本地状态信息,就像在已经运行良好的 deleteTweet 函数中一样。 但这不是故意的。
谁能告诉我为什么会这样?
这里是reducer.js redux tweets 有如下对象
・标题(字符串) ・文本(字符串) ・创建日期(字符串) ・likeingUserIds(array) ・userId(number)
const defaultState = {
user: {
loggedIn: false,
id: 0,
account: ''
},
tweets: []
}
export default function reducer(state = defaultState, action) {
switch (action.type) {
case 'UPDATE_TWEETS':
return {
...state,
tweets: action.tweets
}
default:
return state;
}
}
这里是 actions.js
export function getTweets(tweets){
return {
type: 'UPDATE_TWEETS',
tweets: tweets
}
}
这里是 tweetTable_Comp
class TweetTable_Comp extends Component{
constructor(props){
super(props)
const {dispatch} = props;
this.action = bindActionCreators(actions, dispatch);
this.deleteButtonClicked = this.deleteButtonClicked.bind(this)
this.editButtonClicked = this.editButtonClicked.bind(this)
this.handleChanged = this.handleChanged.bind(this)
this.state = {
filteredTweets: [],
searchWord: ""
}
}
handleChanged(e){
this.setState({[e.target.name]: e.target.value})
}
deleteButtonClicked(id, index){
confirm("削除しますか?") &&
this.deleteTweet(id, index)
}
editButtonClicked(id){
this.props.history.push("/edit/" + id)
}
deleteTweet(id, index){
fetch("http://localhost:8080/twitter/deleteTweet/" + id, {
method: "DELETE"
})
.then((response) => {
if(response.status === 200) {
const newList = this.props.tweets.slice()
newList.splice(index, 1)
this.action.getTweets(newList)
this.setState({filteredTweets: newList})
}
})
}
componentDidMount(){
fetch("http://localhost:8080/twitter/sendAllTweets", {
method: "GET"
})
.then((response) => {
response.json()
.then(json => {
this.action.getTweets(json)
this.setState({filteredTweets: json.slice()})
})
})
}
render(){
return(
<>
<h1 className="text-center">tweet一覧</h1>
<SearchBar searchWord={this.state.searchWord} handleChanged={this.handleChanged}/>
<Container>
<Row>
<Col>
<br/>
<br/>
<Table striped bordered hover>
<thead>
<tr className="text-center">
<th>投稿日</th>
<th>投稿者</th>
<th>タイトル</th>
<th>内容</th>
<th>いいね</th>
<th>削除</th>
<th>編集</th>
</tr>
</thead>
<tbody>
{ this.state.filteredTweets.map((tweet, index) => (
<tr key={tweet.id}>
<td className="text-center">{tweet.createdDate}</td>
<td className="text-center">{tweet.user.account}</td>
<td>{tweet.title}</td>
<td>{tweet.text}</td>
<td className="text-center">
<LikeButton likingUserIds={tweet.likingUserIds} index={index} id={tweet.id} />
</td>
<td className="text-center">
<Button variant="outline-secondary" onClick={() => this.deleteButtonClicked(tweet.id, index)}>
<FontAwesomeIcon icon={faTrashAlt} />
</Button>
</td>
<td className="text-center">
<Button variant="outline-secondary" onClick={() => this.editButtonClicked(tweet.id)}>
<FontAwesomeIcon icon={faEdit} />
</Button>
</td>
</tr>
))
}
</tbody>
</Table>
</Col>
</Row>
</Container>
</>
)
}
}
TweetTable_Comp.propTypes = {
dispatch: PropTypes.func,
tweets: PropTypes.array,
history: PropTypes.object,
user:PropTypes.object
}
function mapStateToProps(state){
return state
}
export default withRouter(connect(mapStateToProps)(TweetTable_Comp))
这里是像Button_Comp
class LikeButton_Comp extends Component {
constructor(props){
super(props)
const {dispatch} = props
this.action = bindActionCreators(actions, dispatch)
this.likeButtonClicked = this.likeButtonClicked.bind(this)
}
likeButtonClicked(func, index){
const data = {
userId:this.props.user.id,
tweetId:this.props.id
}
if(func === "unlike"){
fetch("http://localhost:8080/twitter/like", {
method: "DELETE",
body: JSON.stringify(data)
})
.then((response) => {
if(response.status === 200){
let tweets = this.props.tweets.slice()
const orgLikingUsers = this.props.tweets[index].likingUserIds.slice()
const newLikingUsers = orgLikingUsers.filter(item => item !== this.props.user.id)
tweets[index].likingUserIds = newLikingUsers
this.action.getTweets(tweets)
} else {
alert("処理に失敗しました")
}
})
.catch(error => console.error(error))
} else {
fetch("http://localhost:8080/twitter/like", {
method: "POST",
body: JSON.stringify(data)
})
.then((response) => {
if(response.status === 200){
let tweets = this.props.tweets.slice()
let likingUsers = this.props.tweets[index].likingUserIds.slice()
likingUsers.push(this.props.user.id)
tweets[index].likingUserIds = likingUsers
this.action.getTweets(tweets)
} else {
alert("処理に失敗しました")
}
})
.catch(error => console.error(error))
}
}
render(){
return(
<>
<span>{this.props.likingUserIds.length} </span>
{this.props.tweets.length > 0 && this.props.likingUserIds.includes(this.props.user.id) ?
<Button variant="outline-danger">
<FontAwesomeIcon icon={faHeart} onClick={() => this.likeButtonClicked("unlike", this.props.index)}/>
</Button> :
<Button variant="outline-secondary">
<FontAwesomeIcon icon={faHeart} onClick={() => this.likeButtonClicked("like", this.props.index)}/>
</Button>
}
</>
)
}
}
LikeButton_Comp.propTypes = {
dispatch: PropTypes.func,
user: PropTypes.object,
tweets: PropTypes.array,
likingUserIds: PropTypes.array,
index: PropTypes.number,
id: PropTypes.number
}
function mapStateToProps(state){
return state
}
export default withRouter(connect(mapStateToProps)(LikeButton_Comp))