How can i solve the problem from the book road to react at page 78 ? I keep getting undefine for one of the methods in the table component - javascript

import React, { Component } from 'react';
import './App.css';
const list = [
{
title: 'React',
url: 'https://facebook.github.io/react/',
author: 'Jordan Walke',
num_comments: 3,
points: 4,
objectID: 0,
},
{
title: 'Redux',
url: 'https://github.com/reactjs/redux',
author: 'Dan Abramov, Andrew Clark',
num_comments: 2,
points: 5,
objectID: 1,
},
];
class App extends Component {
state = {
list,
text: 'abc',
searchTerm: ''
}
onDisMiss = (id) => {
const updateList = this.state.list.filter((item) => item.objectID != id)
return () => this.setState({ list: updateList })
}
onSearchChange = (event) => {
this.setState({ searchTerm: event.target.value })
}
isSearched = (searchTerm) => {
return (item) => item.title.toLowerCase().includes(searchTerm.toLowerCase())
}
render() {
const { searchTerm, list } = this.state
return (
<div>
<Search value={searchTerm}
onChange={this.onSearchChange}>Search</Search>
<Table list={list} pattern={searchTerm} onDissMiss={this.onDisMiss} />
</div>
);
}
}
class Search extends Component {
render() {
const { value, onChange, children } = this.props
return (
<div>
<form>
{children}<input type="text" onChange={onChange} value={value} />
</form>
</div>
);
}
}
class Table extends Component {
render() {
const { list, pattern, onDisMiss } = this.props
return (
<div>
{list.filter(isSearched(pattern)).map(item =>
<div key={item.objectID}>
<span><a href={item.url}>{item.title}</a></span>
<span>{item.author}</span>
<span>{item.num_comments}</span>
<span>{item.points}</span>
<span>
<button onClick={onDisMiss(item.objectID)} type="button">Dismiss</button>
</span>
</div>)
}
</div>
);
}
}
export default App;
Road to react Book The Table component related.I get undefined for the isSearched method. how can I fix it so it works correctly its from the book road to react it seems like the book has a few error which I have problems solving because am just learning react. can you help with the solution and why this problem is actually happening

You should put the isSearched method inside the Table class and not the App class

Related

react-sortable-tree - How to get the search API working

According to the API doc there needs to be a searchQuery prop which i've mentioned in my code but the search doesn't seem to be working
API doc doesn't explain how to implement it and the examples available online don't seem to be working on code sandbox.
The only article available which seems to explain search has incorrect code (duplicate props): https://frugalisminds.com/how-to-create-react-sortable-tree/
API Doc: https://www.npmjs.com/package/react-sortable-tree
Below is the code:
import React, { Component } from "react";
import SortableTree from "react-sortable-tree";
import "react-sortable-tree/style.css";
export default class Tree extends Component {
constructor(props) {
super(props);
this.state = {
treeData: [
{ title: "Chicken", children: [{ title: "Egg" }] },
{ title: "Fish", children: [{ title: "fingerline" }] },
],
searchString: ""
};
}
handleSearchOnChange = e => {
this.setState({
searchString: e.target.value,
});
};
render() {
return (
<div style={{ height: 400 }}>
<input
type="search"
onChange={this.handleSearchOnChange}
className="form-control"
/>
<SortableTree
searchQuery={this.state.searchString}
treeData={this.state.treeData}
onChange={treeData => this.setState([...treeData])}
isVirtualized={false}
/>
</div>
);
}
}
missing a searchFocusOffset to highlight the found item and a searchMethod which can be custom defined inside render method as follows:
import React, { Component } from "react";
import SortableTree from "react-sortable-tree";
import "react-sortable-tree/style.css"; // This only needs to be imported once in your app
export default class Tree extends Component {
constructor(props) {
super(props);
this.state = {
treeData: [
{ title: "Chicken", children: [{ title: "Egg" }] },
{ title: "Fish", children: [{ title: "fingerline" }] },
],
searchString: ""
};
}
render() {
// Case insensitive search of `node.title`
const customSearchMethod = ({ node, searchQuery }) =>
searchQuery &&
node.title.toLowerCase().indexOf(searchQuery.toLowerCase()) > -1;
return (
<div style={{ height: 400 }}>
<input
type="search"
onChange={event => this.setState({ searchString: event.target.value })}
className="form-control"
/>
<SortableTree
searchMethod={customSearchMethod}
searchQuery={this.state.searchString}
searchFocusOffset={0}
treeData={this.state.treeData}
onChange={treeData => this.setState([...treeData])}
isVirtualized={false}
/>
</div>
);
}
}

in React How to Update the State of an element in a mapped array of elements?

I have two data objects and 3 hierarchical components below, or in sandbox here. The data contain a list of questions, each rendered with input box right below it that allow multiple replies. However, I don't know how to proper update the state of the correct question after typing in a reply to a particular question.
index.js
import React from 'react';
import { render } from 'react-dom';
import QA from './qa';
//parent of qa.js
const questions = [
{id : 1,
question: "where is the origin of chihuahua?"},
{id : 2,
question: "when does the great migration happen in Africa?"}
]
const answers = [
{
id : 1,
id_question : 1,
answer: "Mexico"
},
{
id : 2,
id_question : 1,
answer: "Argentina"
},
{
id : 3,
id_question : 2,
answer: "Apr"
},
{
id : 4,
id_question : 2,
answer: "May"}
]
export default class App extends React.Component {
state = {
q : questions,
a : answers
}
handleSubmit = (val, index) => {
alert('index',index)
this.setState({
...this.state,
a: [...this.state.a, {id_question: index, answer: val}]
});
}
render() {
console.log(this.state)
return (
questions.map((q, index) =>
<QA
key={index}
question={q.question}
onSubmit={this.handleSubmit}
/>
)
)
}
}
render(<App />, document.getElementById('root'));
qa.js
import React from 'react';
import Answer from './answer';
import "./style.css"
//parent of answer.js
export default class QA extends React.Component {
constructor(props) {
super(props)
this.state = {
text: ""
}
}
render() {
const { question } = this.props
const { text } = this.state
return (
<div class='qa-block'>
<div>Question: {question}</div>
<Answer onSubmit={this.props.onSubmit}/>
</div>
)
}
}
and answer.js
import React from 'react';
const styles = {
backgroundColor: 'lightgray',
};
export default class Answer extends React.Component {
constructor(props) {
super(props)
this.state = {
text: ""
}
}
render() {
const { text } = this.state
return (
<div style={styles}>
<h4>Answers</h4>
<input type="text"
value={text}
onInput={(e) => this.setState({ text: e.target.value })} />
<button onClick={() => this.props.onSubmit(this.state.text)}>Send to the parent</button>
</div>
)
}
}
A few newbie questions:
where do I call index such that setState append to state.answer that right question id and increment answer id by 1?
should I have nested answers as a property of question instead?
Thanks for any help!
You can simply pass questionNo as props to qa & ans components, then retrive through the callback like following:
in index.js
render() {
console.log(this.state)
return (
questions.map((q, index) =>
<QA
questionNo={index}
question={q.question}
onSubmit={this.handleSubmit}
/>
)
)
}
in qa.js
render() {
const { question, questionNo } = this.props
const { text } = this.state
return (
<div class='qa-block'>
<div>Question: {question}</div>
<Answer questionNo={questionNo} onSubmit={this.props.onSubmit}/>
</div>
)
}
in answer.js
render() {
const { text } = this.state
return (
<div style={styles}>
<h4>Answers</h4>
<input type="text"
value={text}
onInput={(e) => this.setState({ text: e.target.value })} />
<button onClick={() => this.props.onSubmit(this.state.text, this.props.questionNo)}>Send to the parent</button>
</div>
)
}
after this you will get index of clicked item in index.js
So to identify the question you need to pass the id_question to the submit button, so if you have the parameter then on the callback you will be able to get it.
once you get you can do a find on the answers array of objects and update the userTyped answer.
handleSubmit = (val, text) => {
const typedAnswer = {...this.state.a.find(ans => ans.id_question === val), userTypedAnswer: text};
this.setState({
...this.state,
a: [...this.state.a, typedAnswer]
});
}
code
index.js
import React from 'react';
import { render } from 'react-dom';
import QA from './qa';
//parent of qa.js
const questions = [
{id: 1,
question: "where is the origin of chihuahua?"},
{id: 2,
question: "when does the great migration happen in africa?"}
]
const answers = [
{id_question: 1,
answer: "Mexico"},
{id_question: 1,
answer: "Argentina"},
{id_question: 2,
answer: "Apr"},
{id_question: 2,
answer: "May"}
]
export default class App extends React.Component {
state = {
q : questions,
a : answers
}
handleSubmit = (val, text) => {
const typedAnswer = {...this.state.a.find(ans => ans.id_question === val), userTypedAnswer: text};
this.setState({
...this.state,
a: [...this.state.a, typedAnswer]
});
}
render() {
return (
<>{
questions.map((q, index) =>
<QA
key={index}
question={q}
onSubmit={this.handleSubmit}
/>
)
}
<p>User Typed Answers and questions after submit</p>
{
this.state.a.map(ans => (
ans.userTypedAnswer && <div>
<span>{ans.id_question}</span>: <span>{ans.userTypedAnswer}</span>
</div>
))
}
</>
)
}
}
render(<App />, document.getElementById('root'));
// answer.js
import React from 'react';
const styles = {
backgroundColor: 'lightgray',
};
export default class Answer extends React.Component {
constructor(props) {
super(props)
this.state = {
text: ""
}
}
render() {
const { text } = this.state
const {onSubmit, qid} = this.props
return (
<div style={styles}>
<h4>Answers</h4>
<input type="text"
value={text}
onInput={(e) => this.setState({ text: e.target.value })} />
<button onClick={() => onSubmit(qid, this.state.text)}>Send to the parent</button>
</div>
)
}
}
qa.js
import React from 'react';
import Answer from './answer';
import "./style.css"
//parent of answer.js
export default class QA extends React.Component {
constructor(props) {
super(props)
this.state = {
text: ""
}
}
render() {
const { question: {question, id}, onSubmit } = this.props
const { text } = this.state
return (
<div class='qa-block'>
<div>Question: {question}</div>
<Answer onSubmit={onSubmit} qid={id}/>
</div>
)
}
}
Working example

Toggling a classname for one button in a list of buttons

I have a list of buttons and I'm trying to toggle the classname when one is clicked. So that only when I click on a specific button is highlighted. I have a TagList component that looks like this:
const Tags = ({tags, onTagClick}) => {
return (
<div className="tags-container">
{ tags.map(tag => {
return (
<span
key={tag.name}
className="tag"
onClick={() => onTagClick(tag)}
>
{tag.name} | {tag.numberOfCourses}
</span>
)
})
}
</div>
)
}
And this is found in the parent component:
onTagClick = (tag) => {
this.filterCourses(tag)
}
render() {
const { tags, courses } = this.state
return (
<div>
<h1> Course Catalog Component</h1>
<Tags tags={tags} onTagClick={this.onTagClick} />
<Courses courses={courses} />
</div>
)
}
I know how I could toggle the class for a single button but I'm a little confused when it comes to a list of buttons. How can I toggle one specifically from a list of buttons? Am I going to need a seperate Tag component and add state to that one component?
EDIT:
This is what my state currently looks like:
constructor(props) {
super(props)
this.state = {
tags: this.sortedTags(),
courses: courses
}
}
And this is what filterCourses looks like:
filterCourses = (tag) => {
this.setState({
courses: courses.filter(course => course.tags.includes(tag.name))
})
}
To start, you would want to give each tag object you're working with a selected property. That will make it easier for you to toggle the class. During the rendering of that markup.
Here is the working sandbox: https://codesandbox.io/s/stupefied-cartwright-6zpxk
Tags.js
import React from "react";
const Tags = ({ tags, onTagClick }) => {
return (
<div className="tags-container">
{tags.map(tag => {
return (
<div
key={tag.name}
className={tag.selected ? "tag selected" : "tag"}
onClick={() => onTagClick(tag)}
>
{tag.name} | {tag.numberOfCourses}
</div>
);
})}
</div>
);
};
export default Tags;
Then in the Parent component, we simply toggle the selected prop (True/False) when the tag is clicked. That will update the tags-array and it gets passed back down to the Child-component which now has the new selected values.
Parent Component
import React from "react";
import ReactDOM from "react-dom";
import Tags from "./Tags";
import Courses from "./Courses";
import "./styles.css";
class App extends React.Component {
state = {
tags: [
{ id: 1, name: "math", numberOfCourses: 2, selected: false },
{ id: 2, name: "english", numberOfCourses: 2, selected: false },
{ id: 3, name: "engineering", numberOfCourses: 2, selected: false }
],
courses: [
{ name: "Math1a", tag: "math" },
{ name: "Math2a", tag: "math" },
{ name: "English100", tag: "english" },
{ name: "English200", tag: "english" },
{ name: "Engineering101", tag: "engineering" }
],
sortedCourses: []
};
onTagClick = tag => {
const tagsClone = JSON.parse(JSON.stringify(this.state.tags));
let foundIndex = tagsClone.findIndex(tagClone => tagClone.id == tag.id);
tagsClone[foundIndex].selected = !tagsClone[foundIndex].selected;
this.setState(
{
tags: tagsClone
},
() => this.filterCourses()
);
};
filterCourses = () => {
const { tags, courses } = this.state;
const selectedTags = tags.filter(tag => tag.selected).map(tag => tag.name);
const resortedCourses = courses.filter(course => {
return selectedTags.includes(course.tag);
});
this.setState({
sortedCourses: resortedCourses
});
};
render() {
const { tags, sortedCourses, courses } = this.state;
return (
<div>
<h1> Course Catalog Component</h1>
<Tags tags={tags} onTagClick={this.onTagClick} />
<Courses courses={!sortedCourses.length ? courses : sortedCourses} />
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

I am not able to remove the list item when i click dismiss?

There are no errors in the code, what is the problem?
I am not able to dismiss the list items and change the state for my component!
What should i do to make my dismiss work and is there a better way as above to do so ??
Here is the code :
import React, { Component } from 'react';
import './App.css';
const list = [
{
title: 'React',
url: 'https://facebook.github.io/react/',
author: 'Jordan Walke',
num_comments: 3,
points: 4,
objectID: 0,
},
{
title: 'facebook github',
url: 'https://facebook.github.io/',
author: 'Janardhan',
num_comments: 3,
points: 6,
objectID: 1,
},
]
class App extends Component {
constructor(props) {
super(props);
this.state = {
list
}
this.onDismiss = this.onDismiss.bind(this);
}
onDismiss(id) {
const isNotID = item => item.objectID !== id;
const updatedList = this.state.list.filter(isNotID)
this.setState({ list: updatedList })
console.log("dismissed??")
}
render() {
return (
<div className="App">
{list.map(item =>
<div key={item.objectID}>
<span>
<a href={item.url}>{item.title}</a>
</span>
<span>{item.author}</span>
<span>{item.points}</span>
<span>{item.num_comments}</span>
<button onClick={() => this.onDismiss(item.objectID)} >Dismiss</button>
</div>
)}
</div>
);
}
}
export default App;
the problem comes from here :
const isNotID = item => item.objectId !== id;
it should be objectID not objectId
Edit
And in the render method, it should be this.state.list.map

React - can't setState values

I'm new to React
when I'm down my soul so weary, troubles come to my code.
because i can't set the state of the addTodo function.
can't add new value to tasks.
my code here:
class App extends Component {
constructor(props) {
super(props)
const tasks = [
{ title: "First Proejct", id: 0 }
]
this.state = {
tasks,
uniqueId: 1
}
}
addTodo = (title) => {
const {
tasks,
uniqueId
} = this.state;
const task = {
title,
id: uniqueId,
}
const newTasks = [...tasks, task]
this.setState({
newTasks, <-- HERE. :(
uniqueId: uniqueId + 1
})
console.log(newTasks)
console.log(task)
}
render() {
return (
<div className="todoApp">
<h1>ToDO APP</h1>
<TodoInput addTodo={this.addTodo} />
<TodoList tasks={this.state.tasks} />
</div>
);
}
}
export default App;
so..
anything that I'm doing wrong?
you should invoke:
this.setState({
tasks: newTasks,
uniqueId: uniqueId + 1
});

Categories