Why my methods for React function components don't work - javascript

I am developing a project with Moviedb api. I created the movie list under the name Movie component. I make my api requests in this component. From the Movie component to the MovieInfo component, I send the release date of the movie and the genres of the movie via props.
But I cannot apply substring and map methods to these properties that come to me in the MovieInfo component with props.
class Movie extends Component {
state = {
movie: [],
loading: false,
actors: [],
directors: [],
visible : 6 // This state is for how many actors rendered.
}
componentDidMount() {
this.setState({
loading: true
})
let moviesEndPoint = `${BASE_URL}/movie/${this.props.match.params.movieId}?api_key=${API_KEY}&language=tr`
let creditsEndPoint = `${BASE_URL}/movie/${this.props.match.params.movieId}/credits?api_key=${API_KEY}`;
this.getMovieWithId(moviesEndPoint);
this.getDirectorsAndActors(creditsEndPoint);
}
getMovieWithId = moviesEndPoint => {
fetch(moviesEndPoint)
.then(response => response.json())
.then((movie) => {
// console.log(movie);
if (movie.overview !== "" && !movie.status_code) {
this.setState({
movie,
loading: false
})
}
else { // if have not turkish overview fetch this
let engEndPoint = `${BASE_URL}/movie/${this.props.match.params.movieId}?api_key=${API_KEY}`
fetch(engEndPoint)
.then(response => response.json())
.then((movie) => {
this.setState({
movie
})
})
}
})
}
getDirectorsAndActors = creditsEndPoint => {
fetch(creditsEndPoint)
.then(response => response.json())
.then((credits) => {
// console.log(credits)
const filterDirector = credits.crew.filter(person => person.job === "Director"); // filter directors from all employees
// console.log(filterDirector)
this.setState({
actors: credits.cast,
directors: filterDirector[0].name,
loading: false
})
})
}
render() {
const { movie, loading, actors, directors, visible } = this.state
const { location } = this.props
return (
<>
{
loading ? <Spinner /> : null
}
{this.state.movie ?
<MovieInfo
movieInfo={movie}
actors={actors}
directors={directors}
searchWord={location.searchWord}
visible = {visible}
loadMore = {this.loadMore}
loading = {loading}
/> : null
}
{
!actors && !loading ? <h1>Film Bulunamadı! </h1> : null
}
</>
)
}
}
This is the non-working code inside my MovieInfo component and my errors like this :
TypeError: Cannot read property 'substring' of undefined
TypeError: Cannot read property 'map' of undefined
const MovieInfo = ({ movieInfo, searchWord, directors, actors, visible, loadMore, loading }) => {
const editReleaseDate = (date) => { //? Idk why doesn't work !
// return date.substring(5).split("-").concat(date.substring(0,4)).join("/")
return date
// console.log(date)
// return date;
}
return (
<Col sm={5} className="movieInfo p-4 animated fadeInRightBig">
<p className = "movie-title" > {movieInfo.title} </p>
<h5 className = "mb-4 text-warning">Yayınlanma Tarihi: <span className = "text-light">{editReleaseDate(movieInfo.release_date)}</span></h5>
<h5 className = "text-warning">Açıklama</h5>
<p>{movieInfo.overview} </p>
<ProgressBar label={`IMDB: ${movieInfo.vote_average}`} animated now = {`${movieInfo.vote_average}`} min={0} max={10} />
<h5 className = "text-warning mt-3">Türü:
{ //? Idk why doesn't work !
// movieInfo.genres.map((genre, i) => {
// return <span key = {i} >{genre.name}</span>
// })
}
</h5>
<h5 className ="mt-2 text-warning">Yönetmen: <span className = "text-light">{directors} </span> </h5>
<div> <i className="fas fa-film fa-5x"></i> </div>
</Col>
)

You have 1 loading state for 2 api calls so once one is finishing it is telling the component that it is done loading even if the second has finished. I split it up into 2 different loading states, loadingMovie & loadingActors.
class Movie extends Component {
state = {
movie: [],
loadingMovie: false,
loadingActors: false,
actors: [],
directors: [],
visible : 6 // This state is for how many actors rendered.
};
componentDidMount() {
this.setState({
...this.state,
loadingMovie: true,
loadingActors: true,
});
let moviesEndPoint = `${BASE_URL}/movie/${this.props.match.params.movieId}?api_key=${API_KEY}&language=tr`;
let creditsEndPoint = `${BASE_URL}/movie/${this.props.match.params.movieId}/credits?api_key=${API_KEY}`;
this.getMovieWithId(moviesEndPoint);
this.getDirectorsAndActors(creditsEndPoint);
}
getMovieWithId = moviesEndPoint => {
fetch(moviesEndPoint)
.then(response => response.json())
.then((movie) => {
// console.log(movie);
if (movie.overview !== "" && !movie.status_code) {
this.setState({
movie,
loadingMovie: false
})
}
else { // if have not turkish overview fetch this
let engEndPoint = `${BASE_URL}/movie/${this.props.match.params.movieId}?api_key=${API_KEY}`
fetch(engEndPoint)
.then(response => response.json())
.then((movie) => {
this.setState({
movie,
loadingMovie: false
});
})
}
})
}
getDirectorsAndActors = creditsEndPoint => {
fetch(creditsEndPoint)
.then(response => response.json())
.then((credits) => {
// console.log(credits)
if (credits && credits.crew) {
const filterDirector = credits.crew.filter(person => person.job === "Director"); // filter directors from all employees
// console.log(filterDirector)
this.setState({
actors: credits.cast,
directors: filterDirector[0].name,
loadingActors: false
})
} else {
console.log('bad credits');
}
})
}
render() {
const { movie, loadingActors, loadingMovie, actors, directors, visible } = this.state;
const { location } = this.props;
return (
<>
{loadingActors || loadingMovie ? <Spinner /> :
(movie.length && actors.length) ?
<MovieInfo
movieInfo={movie}
actors={actors}
directors={directors}
searchWord={location.searchWord}
visible = {visible}
loadMore = {this.loadMore}
loading = {(loadingActors || loadingMovie)}
/> : null
}
{
actors.length && !loadingActors ? <h1>Film Bulunamadı! </h1> : null
}
</>
);
}
}

Related

React fetching data based on previously fetched data

What I want is to fetch all users and then based on the username I fetch movies they have watched. I'm still struggling to understand when a state gets changed, more often than not at the end movies is not in the right order, so that when the MovieInfo-Component gets the data the users get the wrong movies assigned.
My code:
export default class Admin extends Component {
constructor(props) {
super(props);
this.state = {
users: [],
movies: [],
};
}
componentDidMount() {
fetch('https://a-url/users/')
.then((res) => res.json())
.then((data) => {
this.setState(
{
users: data.users,
},
() => {}
);
data.users.map((user) => this.fetchMovies(user.name));
});
}
fetchMovies = (user) => {
fetch('https://a-url/' + user + '/movies/')
.then((res) => res.json())
.then((data) => {
this.setState(
{
movies: [...this.state.movies, ...[data.movies]],
},
() => {}
);
});
};
render() {
const { users, movies } = this.state;
return (
<div className='wum__admin section__padding'>
{users.length > 0 &&
movies.length > 0 &&
users.length === movies.length ? (
<>
{movies &&
users &&
users.map((user, i) => (
<MovieInfo
key={i}
movies={movies[user.id - 1]}
id={user.id}
user={user.name}
/>
))}
</>
) : (
<></>
)}
</div>
);
}
}
If you need to filter movies by user you could change the movies state to be an object where each property (user.name) will have its list of movies:
export default class Admin extends Component {
constructor(props) {
super(props);
this.state = {
users: [],
movies: {},
};
}
...
fetchMovies = (user) => {
fetch('https://a-url/' + user + '/movies/')
.then((res) => res.json())
.then((data) => {
const newMovies = { ...this.state.movies };
newMovies[user] = movies;
this.setState(
{
movies: newMovies,
},
() => {}
);
});
};
render() {
const { users, movies } = this.state;
return (
<div className='wum__admin section__padding'>
{users.length > 0 &&
users.map((user, i) => (
<MovieInfo
key={i}
movies={movies[user.name]}
id={user.id}
user={user.name}
/>
))}
</div>
);
}
}

Set initial class variable from axios request in React

When i call this function
getQuestions = () => {
this.setState({ loading: true })
const { data } = this.props
axios
.get(data.questions)
.then((res) => {
this.setState({
loading: false,
questions: res.data,
})
this.initialQuestions = res.data
})
.catch((err) =>
this.setState({
loading: false,
questions: [],
})
)
}
it updates the array questions in state and array initialQuestions variable in constructor. The state questions represents the values form inputs. The inputs are handled in child component with this code
onChange = (e) => {
const { hasChanged, setQuestions } = this.props
// Update questions
let questions = this.props.questions
questions[e.target.getAttribute('data-id')][e.target.name] =
e.target.value
setQuestions(questions)
}
setQuestions is passed in props as setQuestions={(state) => this.setState({ questions: state })}
So when i change the value of inputs the onChange function is called and it changes the parent component questions in state. But the parent variable this.initialQuestions also is being changed to the questions value from state, but I don't know why
Edit:
That's the code you should be able to run
const { Component } = React;
const Textarea = "textarea";
const objectsEquals = (obj1, obj2) =>
Object.keys(obj1).length === Object.keys(obj2).length &&
Object.keys(obj1).every((p) => obj1[p] === obj2[p])
class QuestionList extends React.Component {
static propTypes = {
questions: PropTypes.array,
removeQuestion: PropTypes.func.isRequired,
hasChanged: PropTypes.func.isRequired,
setQuestions: PropTypes.func.isRequired,
}
constructor(props) {
super(props)
this.questions = props.questions
this.onChange = this.onChange.bind(this)
}
onChange = (e) => {
const { hasChanged, setQuestions } = this.props
// Update questions
let questions = this.props.questions
questions[e.target.getAttribute('data-id')][e.target.name] =
e.target.value
setQuestions(questions)
if (hasChanged && this.questions.length > 0) {
// array of booleans, true if object has change otherwise false
const hasChangedArray = this.props.questions.map(
(_, index) =>
!objectsEquals(
this.questions[index],
this.props.questions[index]
)
)
console.log("hasChangedArray = ", hasChangedArray)
console.log("this.questions[0] = ", this.questions[0])
console.log("this.props.questions[0] = ", this.props.questions[0])
// If true in array than the form has changed
hasChanged(
hasChangedArray.some((hasChanged) => hasChanged === true)
)
}
}
render() {
const { removeQuestion, questions } = this.props
const questionList = questions.map((question, index) => (
<div className="card" key={index}>
<div className="card__body">
<div className="row">
<div className="col-sm-7">
<div className="form-control">
<label className="form-control__label">
Question:
</label>
<input
type="text"
id={`question-${index}`}
data-id={index}
onChange={this.onChange}
name="question"
value={
this.props.questions[index].question
}
className="form-control__input form control__textarea"
placeholder="Pass the question..."
rows="3"
/>
</div>
<div className="form-control">
<label className="form-control__label">
Summery:
</label>
<Textarea
id={`summery-${index}`}
data-id={index}
onChange={this.onChange}
name="summery"
value={this.props.questions[index].summery}
className="form-control__input form-control__textarea"
placeholder="Pass the summery..."
rows="3"
/>
</div>
</div>
</div>
</div>
</div>
))
return questionList
}
}
class Questions extends React.Component {
constructor(props) {
super(props)
this.initialQuestions = []
this.state = {
loading: true,
questions: [],
hasChanged: false,
}
this.getQuestions = this.getQuestions.bind(this)
this.resetForm = this.resetForm.bind(this)
}
resetForm = () => {
console.log("this.initialQuestions =", this.initialQuestions)
this.setState({
questions: this.initialQuestions,
hasChanged: false,
})
}
getQuestions = () => {
this.setState({ loading: true })
const { data } = this.props
// axios
// .get(data.questions)
// .then((res) => {
// this.setState({
// loading: false,
// questions: res.data,
// })
// this.initialQuestions = res.data
// })
// .catch((err) =>
// this.setState({
// loading: false,
// questions: [],
// })
// )
// You can't do a database request so here is some example code
this.setState({
loading: false,
questions: [
{
question: 'example-question',
summery: 'example-summery',
},
{
question: 'example-question-2',
summery: 'example-summery-2',
},
],
})
this.initialQuestions = [
{
question: 'example-question',
summery: 'example-summery',
},
{
question: 'example-question-2',
summery: 'example-summery-2',
},
]
}
componentDidMount = () => this.getQuestions()
render() {
const { loading, questions, hasChanged } = this.state
if (loading) return <h1>Loading...</h1>
return (
<form>
<QuestionList
questions={questions}
hasChanged={(state) =>
this.setState({ hasChanged: state })
}
setQuestions={(state) =>
this.setState({ questions: state })
}
/>
<button
type="reset"
onClick={this.resetForm}
className={`btn ${
!hasChanged
? 'btn__disabled'
: ''
}`}
>
Cancel
</button>
<button
type="submit"
className={`btn btn__contrast ${
!hasChanged
? 'btn__disabled'
: ''
}`}
>
Save
</button>
</form>
)
}
}
ReactDOM.render(<Questions />, document.querySelector("#root"));
<script src="https://unpkg.com/react#17/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom#17/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/prop-types#15/prop-types.min.js"></script>
<div id="root"></div>
Both state questions and class variable initialQuestions hold reference of res.data. Now when you update questions in onChange method, you are updating it by reference i.e directly mutating it and hence the class variable is also updated
You must not update it by reference but clone and update like below
onChange = (e) => {
const { hasChanged, setQuestions } = this.props
// Update questions
let questions = this.props.questions
questions = questions.map((question, idx) => {
if(idx === e.target.getAttribute('data-id')) {
return {
...question,
[e.target.name]: e.target.value
}
}
return question;
});
setQuestions(questions)
}

Error when converting a class component to a functional component

i am trying to convert my class component to a functionnal component but my filters are not working anymore.
the main error is when I want to convert listProducts because I don't know how to define the prevState with useState for that case
how can update the state for case?
this is my code
class component
class ListShopping extends Component{
constructor(props) {
super(props);
this.state = {
size: "",
sort: "",
cartItems: [],
products: [],
filteredProducts: []
};
}
componentDidMount() {
fetch("http://localhost:8000/products")
.then(res => res.json())
.catch(err =>
fetch("db.json")
.then(res => res.json())
.then(data => data.products)
)
.then(data => {
this.setState({ products: data });
this.listProducts();
});
}
listProducts = () => {
this.setState(state => {
if (state.sort !== "") {
state.products.sort((a, b) =>
state.sort === "lowestprice"
? a.price < b.price
? 1
: -1
: a.price > b.price
? 1
: -1
);
} else {
state.products.sort((a, b) => (a.id > b.id ? 1 : -1));
}
if(state.size !== ""){
return {
filteredProducts: state.products.filter(
a => a.availableSizes.indexOf(state.size.toUpperCase()) >= 0
)
}
}
return { filteredProducts: state.products };
});
};
handleSortChange = e => {
this.setState({ sort: e.target.value });
this.listProducts();
};
handleSizeChange = e => {
this.setState({ size: e.target.value });
this.listProducts();
};
render() {
return (
<div className="container">
<h1>E-commerce Shopping Cart Application</h1>
<hr />
<div className="row">
<div className="col-md-9">
<Filter
count={this.state.filteredProducts.length}
handleSortChange={this.handleSortChange}
handleSizeChange={this.handleSizeChange}
/>
<hr />
<Products
products={this.state.filteredProducts}
/>
</div>
</div>
</div>
);
}
}
functionnal component
const ListShopping = () => {
const [data, setData] = useState({
products : [],
filteredProducts : [],
sort : '',
size : ''
})
const {products, filteredProducts, sort, size} = data;
const fetchApi = () => {
axios.get(`http://localhost:8000/products`)
.then(response => response.data)
.then(data => {
setData({...data, products: data});
})
}
const listProducts = () => {
};
const handleSortChange = e => {
setData({...e, sort: e.target.value})
listProducts();
};
const handleSizeChange = e => {
setData({...e, size: e.target.value})
listProducts();
};
useEffect(()=> {
fetchApi()
}, [])
return(
<div className="container">
<h1>E-commerce Shopping Cart Application</h1>
<hr />
<div className="row">
<div className="col-md-9">
<Filter
count={filteredProducts.length}
handleSortChange={handleSortChange}
handleSizeChange={handleSizeChange}
/>
<hr />
<Products
products={filteredProducts}
/>
</div>
</div>
</div>
)
}
Try this
const listProducts = () => {
setData(data => {
if (data.sort !== '') {
data.products.sort((a, b) =>
data.sort === 'lowestprice'
? a.price < b.price
? 1
: -1
: a.price > b.price
? 1
: -1,
);
} else {
data.products.sort((a, b) => (a.id > b.id ? 1 : -1));
}
if (data.size !== '') {
return {
...data,
filteredProducts: data.products.filter(
a => a.availableSizes.indexOf(data.size.toUpperCase()) >= 0,
),
};
}
return { ...data, filteredProducts: data.products };
});
};
Suppose you have a state like this
const [todos, setTodos] = useState([1,2,3,4,5,6,7]);
Method 1:
Now if you want to get prevState from this hook try this way
setTodos(oldTodo => {
oldTodo.push(1000);
setTodos(oldTodo)
})
this oldTodo work the same way the prevState works.
Method 2:
const listProducts = () => {
let oldState = todos
//Now do what you want to do with it. modify the oldTodo
setTodos(oldTodo);
}
I prefer the second method because it gives me more flexibility to change modify the state and if you cannot manage the state properly in the first method or if it finds any bug then it will return undefined so I prefer to work taking the whole state in a temporary variable and after work is done set it

Set the setState to the searched books array to made it back to the blank array in case of invalid query

for a React project I have to setState the searched books array back to the blank array in case of invalid query, but I couldn't find a solution to my problem at the moment.
This is my code:
search_books = (val) => {
if (val.length !== 0 ) {
BooksAPI.search( val, 10 ).then((books) => {
if (books.length > 0 ) {
books = this.changeBookShelf(books)
this.setState(() => {
return {Books: books}
})
}
})
} else {
this.setState({Books: [], query: ''})
}
}
and this is the full code in case you'll need it:
import React, {Component} from 'react'
import {Link} from 'react-router-dom'
import * as BooksAPI from '../BooksAPI'
import Book from './Book'
import {PropTypes} from 'prop-types'
class BookSearch extends Component {
state = {
Books: [],
query: ''
}
static propTypes = {
onChange: PropTypes.func.isRequired,
myBooks: PropTypes.array.isRequired
}
handleChange = ( event ) => {
var value = event.target.value
this.setState(() => {
return {query: value}
})
this.search_books(value)
}
changeBookShelf = ( books ) => {
let all_Books = this.props.myBooks
for ( let book of books ) {
book.shelf = "none"
}
for ( let book of books ) {
for ( let b of all_Books ) {
if ( b.id === book.id ) {
book.shelf = b.shelf
}
}
}
return books
}
search_books = (val) => {
if (val.length !== 0 ) {
BooksAPI.search( val, 10 ).then((books) => {
if (books.length > 0 ) {
books = this.changeBookShelf(books)
this.setState(() => {
return {Books: books}
})
}
})
} else {
this.setState({Books: [], query: ''})
}
}
add_book = ( book, shelf ) => {
this.props.onChange( book, shelf )
}
render() {
return (
<div className="search-books">
<div className="search-books-bar">
<Link to='/' className="close-search">Close</Link>
<div className="search-books-input-wrapper">
<input type="text" placeholder="Search by title or author" value={this.state.query} onChange={this.handleChange}/>
</div>
</div>
<div className="search-books-results">
<ol className="books-grid">
{this.state.query.length > 0 && this.state.Books.map((book, index) => (<Book book={book} key={index} onUpdate={(shelf) => {
this.add_book( book, shelf )
}}/>))}
</ol>
</div>
</div>
)
}
}
export default BookSearch;
It's the last step but I can't figure out how to make the search launching an error if an invalid query is written in the search bar.
Looks like you're properly setting it to an empty array when there is no query, but forgetting to do so when there is a query string but no matching books. You just need to add an else statement in your .then function:
search_books = (val) => {
if (val.length !== 0 ) {
BooksAPI.search( val, 10 ).then((books) => {
if (books.length > 0 ) {
books = this.changeBookShelf(books)
this.setState(() => {
return {Books: books}
})
} else {
this.setState({Books: []})
}
})
} else {
this.setState({Books: [], query: ''})
}
You can add an error object to the state and use it to render a message:
state = {
Books: [],
query: '',
error: {
isError: false,
message: ''
}
}
Inside your search logic you can change the error object:
search_books = (val) => {
if (val.length !== 0 ) {
BooksAPI.search( val, 10 ).then((books) => {
if (books.length > 0 ) {
books = this.changeBookShelf(books)
this.setState(() => {
return {Books: books, error: {isError: false, message: ''}}
})
} else{
this.setState(() => {
return {Books: [], error: {isError:true, message:"No books"}}
})
}
})
} else {
this.setState({Books: [], query: '', {isError:true, message:"No books"}})
}
}
In your render method you can check the error object and display an error if needed:
render(){
// ...
error.isError && <div>{error.message}</div>
//...
}

How to show information from API when using search box in ReactJS?

I'm using the Star Wars API to build a React JS project. The aim of my app is to be able to search for characters.
Here is my code for the search component in the my app.
At the moment I'm able to retrieve data the API and show the information on the page but I can't work out how to show this information when it's searched for.
Any ideas?
import React, { Component } from 'react';
class Search extends Component {
constructor(props){
super(props)
this.state = {
query:'',
peoples: [],
}
}
onChange (e){
this.setState({
query: e.target.value
})
if(this.state.query && this.state.query.length > 1) {
if(this.state.query.length % 2 === 0){
this.componentDidMount()
}
}
}
componentDidMount(){
const url = "https://swapi.co/api/people/";
fetch (url,{
method:'GET'
}).then(results => {
return results.json();
}).then(data => {
let peoples = data.results.map((people) => {
return(
<ul key={people.name}>
<li>{people.name}</li>
</ul>
)
})
this.setState({peoples: peoples});
console.log("state", peoples)
})
}
render() {
return (
<form>
<input
type="text"
className="search-box"
placeholder="Search for..."
onChange={this.onChange.bind(this)}
/>
{this.state.peoples}
</form>
)
}
}
export default Search
You could put your fetch in a separate function instead of in componentDidMount and call that when the component mounts and when your query changes.
Since you might be creating multiple requests if the user types quickly, you could use a debounce to only send one request, or use something that verifies that you always use the result of the latest request, like e.g. a token.
Example
class Search extends Component {
token = null;
state = {
query: "",
people: []
};
onChange = e => {
const { value } = e.target;
this.setState({
query: value
});
this.search(value);
};
search = query => {
const url = `https://swapi.co/api/people?search=${query}`;
const token = {};
this.token = token;
fetch(url)
.then(results => results.json())
.then(data => {
if (this.token === token) {
this.setState({ people: data.results });
}
});
};
componentDidMount() {
this.search("");
}
render() {
return (
<form>
<input
type="text"
className="search-box"
placeholder="Search for..."
onChange={this.onChange}
/>
{this.state.people.map(person => (
<ul key={person.name}>
<li>{person.name}</li>
</ul>
))}
</form>
);
}
}
You have to define it in diff function to manage easy.
import React, { Component } from 'react';
class Search extends Component {
constructor(props) {
super(props)
this.state = {
query: null,
peoples: [],
}
}
componentDidMount() {
this.serachPeople(this.state.query);
}
onChange(e) {
this.setState({ query: e.target.value }, () => {
if (this.state.query && this.state.query.length > 1) {
if (this.state.query.length % 2 === 0) {
this.serachPeople(this.state.query);
}
} else {
this.serachPeople(this.state.query);
}
})
}
serachPeople(query) {
const url = "https://swapi.co/api/people/";
if (query) {
// if get value ion query so filter the data based on the query.
fetch(url, {
method: 'GET'
}).then(results => {
return results.json();
}).then(data => {
let peoples = data.results.filter(people => people.name === query).map((people) => {
return (
<ul key={people.name}>
<li>{people.name}</li>
</ul>
)
})
this.setState({ peoples: peoples });
console.log("state", peoples)
})
} else {
fetch(url, {
method: 'GET'
}).then(results => {
return results.json();
}).then(data => {
let peoples = data.results.map((people) => {
return (
<ul key={people.name}>
<li>{people.name}</li>
</ul>
)
})
this.setState({ peoples: peoples });
console.log("state", peoples)
})
}
}
render() {
return (
<form>
<input
type="text"
className="search-box"
placeholder="Search for..."
onChange={this.onChange.bind(this)}
/>
{this.state.peoples}
</form>
)
}
}
export default Search;
I hope this will help for u. Let me know if u have any query.

Categories

Resources